Java并发——使用Condition线程间通信

1. Java中线程协作的最常见的两种方式:利用Object.wait()、Object.notify()和使用Condition

(1)复习一下Object.wait()、Object.notify()

在java中,对于任意一个java对象,它都拥有一组定义在java.lang.Object上监视器方法,包括wait(),wait(long timeout),notify(),notifyAll(),这些方法配合synchronized关键字一起使用可以实现等待/通知模式。

以前的文章:https://blog.csdn.net/zhm1563550235/article/details/84259542

(2)什么是Condition接口?

Condition接口也提供了类似Object监视器的方法,通过与Lock配合来实现等待/通知模式。

2. Condition接口 

接口Condition把Object的wait和notification方法(包括wait()、notify()、notifyAll())分解到不同的条件对象中。通过把这些条件和任意Lock实现的使用组合起来,起到让每个对象上具有多重等待集合的作用。这里Lock取代了同步方法、同步代码块,condition取代了Object的wait、notification方法。 

3. Condition声明的方法

方法名称 描述
void await() 在接收到信号或被中断以前,强制调用线程一直等待。
boolean await(long time, TimeUnit unit) 在接收到信号、被中断,或者超过指定的等待时间之前,强制调用线程一直等待。

同样是在await()基础上增加了超时响应,不同的是:

  • 可以自定义超时时间单位;
  • 返回值返回true/false,在time之前被唤醒,返回true,超时返回false。
long awaitNanos(long nanosTimeout)

在接收到信号,被中断,或者超过指定的等待时间之前,强制调用线程一直等待。同样是在await()基础上增加了超时响应,不同的是:

返回值表示当前剩余的时间,如果在nanosTimeout之前被唤醒,返回值 = nanosTimeout - 实际消耗的时间,返回值 <= 0表示超时;

void awaitUninterruptibly() 在接收到信号之前,强制当前线程一直等待。
boolean awaitUntil(Date deadline) 在接收到信号、被中断,或者超过指定的截止时间之前,强制当前的线程一直等待。
void signal() 唤醒一个等待中的线程。
void signalAll() 唤醒所有等待中的线程。

4. 获取Condition 

Condition实例实质上被绑定到一个锁上。一个锁内部可以有多个Condition,即有多路等待和通知。要为特定 Lock 实例获得 Condition 实例,请使用其 newCondition() 方法。

Conditon newCondition() 返回用来与当前Lock实例一起使用的Condition实例。

类似于 object.wait()和object.notify()的功能。object.wait()与object.notify()需要结合synchronized使用。Condition需要结合ReentrantLock使用。

5. Condition与循环一起使用,防止"虚假唤醒"

在等待Condition时,允许发生"虚假唤醒",这通常作为对基础平台语义的让步。若使用"if(!条件)"则被"虚假唤醒"的线程可能继续执行。所以"while(!条件)"可以防止"虚假唤醒"。建议总是假定这些"虚假唤醒"可能发生,因此总是在一个循环中等待。

6. Condition的使用

程序案例来自:http://www.cnblogs.com/dolphin0520/p/3920385.html

(1)使用Object的wait()和notify()实现生产者消费者: 

public class Test {
    private int queueSize = 10;
    private PriorityQueue<Integer> queue = new PriorityQueue<Integer>(queueSize);
      
    public static void main(String[] args)  {
        Test test = new Test();
        Producer producer = test.new Producer();
        Consumer consumer = test.new Consumer();
          
        producer.start();
        consumer.start();
    }
      
    class Consumer extends Thread{
          
        @Override
        public void run() {
            consume();
        }
          
        private void consume() {
            while(true){
                synchronized (queue) {
                    while(queue.size() == 0){
                        try {
                            System.out.println("队列空,等待数据");
                            queue.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            queue.notify();
                        }
                    }
                    queue.poll();          //每次移走队首元素
                    queue.notify();
                    System.out.println("从队列取走一个元素,队列剩余"+queue.size()+"个元素");
                }
            }
        }
    }
      
    class Producer extends Thread{
          
        @Override
        public void run() {
            produce();
        }
          
        private void produce() {
            while(true){
                synchronized (queue) {
                    while(queue.size() == queueSize){
                        try {
                            System.out.println("队列满,等待有空余空间");
                            queue.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            queue.notify();
                        }
                    }
                    queue.offer(1);        //每次插入一个元素
                    queue.notify();
                    System.out.println("向队列取中插入一个元素,队列剩余空间:"+(queueSize-queue.size()));
                }
            }
        }
    }
}

(2)使用Condition实现消费者生产者

public class Test {
    private int queueSize = 10;
    private PriorityQueue<Integer> queue = new PriorityQueue<Integer>(queueSize);
    private Lock lock = new ReentrantLock();
    private Condition notFull = lock.newCondition();
    private Condition notEmpty = lock.newCondition();
     
    public static void main(String[] args)  {
        Test test = new Test();
        Producer producer = test.new Producer();
        Consumer consumer = test.new Consumer();
          
        producer.start();
        consumer.start();
    }
      
    class Consumer extends Thread{
          
        @Override
        public void run() {
            consume();
        }
          
        private void consume() {
            while(true){
                lock.lock();
                try {
                    while(queue.size() == 0){
                        try {
                            System.out.println("队列空,等待数据");
                            notEmpty.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    queue.poll();                //每次移走队首元素
                    notFull.signal();
                    System.out.println("从队列取走一个元素,队列剩余"+queue.size()+"个元素");
                } finally{
                    lock.unlock();
                }
            }
        }
    }
      
    class Producer extends Thread{
          
        @Override
        public void run() {
            produce();
        }
          
        private void produce() {
            while(true){
                lock.lock();
                try {
                    while(queue.size() == queueSize){
                        try {
                            System.out.println("队列满,等待有空余空间");
                            notFull.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    queue.offer(1);        //每次插入一个元素
                    notEmpty.signal();
                    System.out.println("向队列取中插入一个元素,队列剩余空间:"+(queueSize-queue.size()));
                } finally{
                    lock.unlock();
                }
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/zhm1563550235/article/details/84618185