线程同步:读写锁(四)

并发编程中有一个典型的问题是生产者-消费者(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();
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值