首页 > 技术文章 > Java多线程 ReentrantLock、Condition 实现生产者、消费者协作模式

haiyangwu 2019-02-27 15:06 原文

一、锁接口 Lock,ReadWriteLock:

  1、Lock,实现类有ReentractLock、WriteLock、ReadLock;

  2、ReadWriteLock,主要实现类是ReentrantReadWriteLock,有两个方法 writeLock()、readLock() ,返回值是 WriteLock,ReadLock,这两类继承与Lock接口;

  3、常用方法:

    lock()  /  unlock():获取/释放锁,lock()会阻塞直到成功

    lockInterruptibly():与lock() 不同的是它可以响应中断,如果被其他线程中断了,则抛出InterruptedException

    tryLock() / tyrLock(long time, TimeUnit unit):只是尝试获取锁,立即返回,返回值为 boolean。无参数不阻塞,有参数会根据设置的时间阻塞等待,如果发生中断抛出InterruptedException

    newCondition:新建一个条件,一个lock可以关联多个条件

二、对比 ReentractLock 和 synchornized:

    相比synchronized,ReentractLock可以实现与synchronized 相同的语义,而且支持以非阻塞方法获取锁,可以响应中断,可以限时,更为灵活。不过,synchronized 的使用更为简单,写的代码更少,也不容易出错。

三、Condition:

  锁用于解决竞态条件问题,条件是线程间的协作机制。显示锁与synchronized 相对应,而显式条件与wait/notify 相对应。wait/notify 与synchronized 配合使用,显式条件与显示锁配合使用。

  1、声明:Condition c = reentractLock.newCondition();

  2、常用方法:

    await() / signal():等待/通知,使用时需获取锁,await() 发生中断,抛出 InterruptedException,但中断标志位会被清空。awaitUniterruptibly() 不响应中断              

四、ReentractLock、Condition 搭配使用:

/**
 * ReentrantLock 显式锁
 *
 * Condition 显式条件
 *
 * 生产者、消费者协作模式
 */

public class ReentrantLockTest {

    private  int e = 1;

    private  int num = 30;

    //private  BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(num);

    private Queue<Integer> queue = new ArrayDeque<>(num);

    private  Lock lock = new ReentrantLock();

    private  Condition queueFull = lock.newCondition();

    private  Condition queueEmpty = lock.newCondition();

    public static void main(String[] args) throws InterruptedException {

        ReentrantLockTest reentrantLockTest = new ReentrantLockTest();

        for(int i = 0; i < reentrantLockTest.num; i++){
            new Thread(() -> {
                try {
                    reentrantLockTest.producer();

                    Thread.sleep((int)(Math.random() * 100));
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
            }).start();
        }

        for(int i = 0; i < reentrantLockTest.num; i++){
            new Thread(() -> {
                try {
                    reentrantLockTest.consumer();
                    Thread.sleep((int)(Math.random() * 100));
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
            }).start();
        }

    }

    public  void producer() throws InterruptedException {
        lock.lockInterruptibly();
        try{
            while (queue.size() == num){
                queueFull.await();
            }

            queue.add(e++);
            System.out.println("producer" + Arrays.toString(queue.toArray()));
            queueEmpty.signal();
        }finally {
            lock.unlock();
        }

    }

    public  void consumer() throws InterruptedException {
        lock.lockInterruptibly();
        try{
            while (queue.isEmpty()){
                queueEmpty.await();
            }

            System.out.println("poll:" + queue.poll() + ",comsumer" + Arrays.toString(queue.toArray()));
            queueFull.signal();
        }finally {
            lock.unlock();
        }

    }

}

 

推荐阅读