线程同步:读写锁(四)

来源:互联网 发布:linux下svn 钩子函数 编辑:程序博客网 时间:2024/05/01 08:43

    • 使用synchronized关键字
    • 使用ReadWriteLock接口

并发编程中有一个典型的问题是生产者-消费者(Producer-Consumer)问题。我们有一个数据缓冲区,一个或者多个生产者将数据存入这个缓冲区,一个或者多个数据消费者将数据从缓冲区中取走。

使用synchronized关键字

只是用synchronized关键字会有诸多限制。如果缓冲区是满的,生产者不能再放入新的数据,如果缓冲区是空的,消费者不能取到数据。
对于这些场景java在Object类中提供了wait()、notify()、notifyAll()方法

/** * @Desciption 缓冲区 *  * @Author SuFH */public class EventStorage {    private int maxSize;    private LinkedList<Long> storage;    public EventStorage(int max) {        //初始化缓冲区        this.maxSize = max;        this.storage = new LinkedList<Long>();    }    public synchronized void set() {        while (storage.size() == maxSize) {            try {                wait();//挂起当前同步代码块            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }        storage.add(System.currentTimeMillis());        System.out.printf("Set: %d\n", storage.size());        // notify();//唤醒一个正在等待该对象的线程,但需要确定不会造成死锁        notifyAll();// 唤醒所有正在等待该对象的线程。    }    public synchronized void get() {        while (storage.size() == 0) {            try {                wait();            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }        System.out.printf("Get: %d : %s\n", storage.size(), storage.poll());        notifyAll();    }}

执行:

public class Test {    public static void main(String[] args) {        EventStorage storage = new EventStorage(10);        Producer producer = new Producer(storage);        Thread thread = new Thread(producer);        Consumer consumer = new Consumer(storage);        Thread thread2 = new Thread(consumer);        thread.start();        thread2.start();    }}class Producer implements Runnable {    private EventStorage storage;    public Producer(EventStorage storage) {        super();        this.storage = storage;    }    @Override    public void run() {        // TODO Auto-generated method stub        for (int i = 0; i < 100; i++) {            this.storage.set();            System.out.println("Producer---"+i);        }    }}class Consumer implements Runnable {    private EventStorage storage;    public Consumer(EventStorage storage) {        super();        this.storage = storage;    }    @Override    public void run() {        // TODO Auto-generated method stub        for (int i = 0; i < 100; i++) {            this.storage.get();            System.out.println("Consumer---"+i);        }    }}

数据存储的EventStorage类中的set()和get()。
set()方法检查存储列表storage是否还有空间,如果满了,调用wait()挂起线程释放控制这个代码块的对象,等待空余空间出现。该代码块的唤醒却决于其他线程调用当前对象的notifyAll()唤醒等待线程来竞争锁。
get()与之不同之处在于条件是判别空间中无数据则挂起。

使用ReadWriteLock接口

ReadWriteLock与它的唯一实现类ReentrantReadWriteLock。这个类有两个锁分别是读操作锁与写操作锁。其中读操作锁允许多个线程同时访问,但是写操作锁至允许一个线程进行访问,并且在进行写操作时,不能进行读操作

/** * @Desciption 缓冲区 *  * @Author SuFH */public class PricesInfo {    private double prices1;    private double prices2;    private ReadWriteLock lock;    public PricesInfo() {        this.prices1 = 0.1;        this.prices2 = 0.2;        this.lock = new ReentrantReadWriteLock();    }    /**读操作     * @return prices1     */    public double getPrices1() {        lock.readLock().lock();        double value=prices1;        lock.readLock().unlock();        return value;    }    /**读操作     * @return prices2     */    public double getPrices2() {        lock.readLock().lock();        double value=prices2;        lock.readLock().unlock();        return value;    }    /**写操作     * @param prices1     * @param prices2     */    public void setPrices(double prices1, double prices2) {        lock.writeLock().lock();        this.prices1 = prices1;        this.prices2 = prices2;        lock.writeLock().unlock();    }}

执行:

public class Test {    public static void main(String[] args) {        PricesInfo info = new PricesInfo();        Read[] reads = new Read[5];        Thread[] thread = new Thread[5];        for (int i = 0; i < 5; i++) {            reads[i] = new Read(info);            thread[i]=new Thread(reads[i]);        }        Writer writer=new Writer(info);        Thread thread2=new Thread(writer);        for (int i = 0; i < 5; i++) {            thread[i].start();        }        thread2.start();    }}class Read implements Runnable {    private PricesInfo info;    public Read(PricesInfo info) {        // TODO Auto-generated constructor stub        this.info = info;    }    @Override    public void run() {        // TODO Auto-generated method stub        for (int i = 0; i < 10; i++) {            System.out.printf("%s Price 1: %f\n", Thread.currentThread().getName(), this.info.getPrices1());            System.out.printf("%s Price 2: %f\n", Thread.currentThread().getName(), this.info.getPrices2());        }    }}class Writer implements Runnable {    private PricesInfo info;    public Writer(PricesInfo info) {        this.info = info;    }    @Override    public void run() {        // TODO Auto-generated method stub        for (int i = 0; i < 3; i++) {            System.out.println("Writer: Attempt to modify the price.");            this.info.setPrices(Math.random()*10,Math.random()*5);            System.out.println("Writer: Prices have been modfied.");            try {                Thread.sleep(2);            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }    }}
原创粉丝点击