【java多线程】(7)---Condition

Condition

一、Condition概述

       在线程的同步时可以使一个线程阻塞而等待一个信号,同时放弃锁使其他线程可以能竞争到锁。

       在synchronized中我们可以使用Object的wait()和notify方法实现这种等待和唤醒。

       在Lock可以实现相同的功能就是通过Condition。Condition中的await()和signal()/signalAll()就相当于Object的wait()和notify()/notifyAll()。

除此之外,Condition还是对多线程条件进行更精确的控制。notify()是唤醒一个线程,但它无法确认是唤醒哪一个线程。 但是,通过Condition,就能明确的指定唤醒读线程。

二、Condition和Object案例对比

       案例说明:生成者在仓库满时,进入等待状态,同时唤醒消费者线程,消费者在仓库为空时,进入等待。同时唤醒生产者线程。

1、采用await()和signal()方式

(1)测试类

public class ConditionLockTest {

    public static void main(String[] args){

        //相当于仓库
        Depot depot=new Depot();
        
      //创建两个生产者一个消费者
        Producer producer1=new Producer(depot);
        Producer producer2=new Producer(depot);
        Consumer consumer1=new Consumer(depot);
        
      //采用线程池方式
        Executor executors=Executors.newFixedThreadPool(5);
        executors.execute(producer1);
        executors.execute(producer2);
        executors.execute(consumer1);
    }
}

//生产者
class Producer implements  Runnable {

    Depot depot;
    public Producer(Depot depot){
        this.depot=depot;
    }
    public void  run(){
     while(true){
        depot.prod();
       }
    }
}

//消费者
class Consumer implements  Runnable{
    
    Depot depot;  
    public Consumer(Depot depot){
        this.depot=depot;
    }
    public void run(){
     while(true){
        depot.consum();
      }
   }
}

(2)仓库类

public class Depot {
   //初始仓库为0,最大为10,超过10生产者停止生产
    private int size;
    private int maxSize=10;

    private Condition prodCondition;
    private Condition consumCondition;

    private Lock lock;
    public Depot(){

        this.size=0;
        this.lock=new ReentrantLock();
        //可以看出Condition对象依赖于Lock锁
        this.prodCondition=this.lock.newCondition();
        this.consumCondition=this.lock.newCondition();
    }

    /*
     * 生产者生产方法
     */
    public void prod(){

        lock.lock();
        try{
          //如果生产超过max值,则生产者进入等待
            while(size+1>maxSize){
                try {
                    System.out.println(Thread.currentThread().getName()+"生产者进入等待状态");
                    prodCondition.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            size+=1;        
            System.out.println(Thread.currentThread().getName()+" 生产了一个 "+1+" 总共还有 "+size);
            
            //唤醒消费者线程
            consumCondition.signal(); 

        }finally {
            lock.unlock();
        }
    }

    /*
     * 消费者消费方法
     */
    public void consum(){

        lock.lock();
        try{
            //如果当前大小减去要消费的值,如果小于0的话,则进入等待
            while(size-1<0){
                try {
                     System.out.println(Thread.currentThread().getName()+" 消费者进入等待状态");
                    consumCondition.await();
                   

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            size-=1;
            System.out.println(Thread.currentThread().getName()+" 消费者消费了 "+1+" 个,总共还有 "+size);
            //唤醒生产者线程
            prodCondition.signal(); 
        }finally {
            lock.unlock();
        }
    }
}

运行结果(截取部分图)

根据结果分析可以得出:
      生产者生产产品,当超过10个,生产者会处于等待状态,直到消费者消费者消费了一个产品,生产者才会重新唤醒。

 2、采用wait()和notifyAll()方法

 (1)仓库类代码(测试类代码不变)

public class Depot {
   //初始仓库为0,最大为10,超过10生产者停止生产
    private int size;
    private int maxSize=10;

    public Depot(){
        this.size=0;
    }

    /*
     * 生产者生产方法
     */
    public synchronized void prod(){

        try{
          //如果生产超过max值,则生产者进入等待
            while(size+1>maxSize){
                try {
               //采用wait方法
                      wait();
                   System.out.println(Thread.currentThread().getName()+"生产者进入等待状态");         
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            size+=1;        
            System.out.println(Thread.currentThread().getName()+" 生产了一个 "+1+" 总共还有 "+size);
            
            //唤醒所有线程
             notifyAll();
         
        }finally {     
        }
    }

    /*
     * 消费者消费方法
     */
    public synchronized void consum(){

        try{
            //如果当前大小减去要消费的值,如果小于0的话,则进入等待
            while(size-1<0){
                try {
                     wait();
                     System.out.println(Thread.currentThread().getName()+" 消费者进入等待状态");
                  
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
          
            size-=1;
            System.out.println(Thread.currentThread().getName()+" 消费者消费了 "+1+" 个,总共还有 "+size);
            //唤醒所有线程
            notifyAll();
          
        }finally {
        }
    }
}    

运行结果:

对比:

       首先可以看出两个都可以实现生产者消费者的工作,不过可以发现Condition的signal相对于Object的notify最大有点就是它可以唤醒指定的线程,

比如这里可以指定唤醒生产线程或者消费线程,而用notify是不能唤醒指定线程的,你只能通过notifyAll来唤醒所有。

 想太多,做太少,中间的落差就是烦恼。想没有烦恼,要么别想,要么多做。少校【14】

猜你喜欢

转载自www.cnblogs.com/qdhxhz/p/9206076.html