Condition接口的用法和示例

条件变量:线程进入临界区域后,往往需要等待满足某个条件才能继续执行。例如,消费者需要等待缓冲区有产品后才能消费,用户只有在银行账户上有金额的时候能能取款等。
        在JDK1.5之前,主要用wait()、notify()和notifyAll()方法执行条件操作中的等待和唤醒机制,JDK1.5之后版本开始,引入了条件变量(Condition Variables)。条件变量也被称为条件队列(Condition Queue)。是由Condition定义的,
        它可以让一个线程在条件不满足的情况下一直等下去,直到由其它线程唤醒它。
        接口Condition 与JDK1.5之前的版本 wait()、notify()和notifyAll()方法的不同,主要由四点:
        1)它允许在一个对象上有多个等待集合。
        2)当synchronized锁被Lock锁对象替换后,相应对象的监视器方法wait()、notify()和notifyAll()操作也要用await()、signal()和signalAll()方法操作替换。
        3)Condition对象与对象监视器上的方法wait()、notify和notifyAll()的行为和语义不同。Condition对象在唤醒线程的次序上与对象监视器上的方法不同,并且唤醒时不要求一定持有Lock对象锁。
        4)Condition接口的实例是一个对象,在synchronized控制的范围内,可以在Condition对象实例上条用方法wait、notify()和notifyAll()。
        由于要对共享状态进行操作,所以Codition对象一般是要包含在同步操作中,Lock对象为Condition提供了这种同步操作。Condition对象通常被绑定到Lock对象上,要创建一个Condition对象的实例,须用Lock方法 newCondition();
        例如:
        Lock lock  = new ReentrantLock();
        Condition notfull = lock.newCondition();
        Condition empty = lock.newCondition();
        接下来是Condition接口的方法:
        
        1、await()方法:定义如下
        void await() throws InterruptedExcetion
        当一个线程调用了await()方法后,线程进入阻塞状态,这时线程本省是无法解除这种状态的,需要其他的线程来帮忙,否则线程永远无法执行。阻塞状态解除的条件:
        1)某一个线程在当前条件对象上调用了方法signal()方法,而该线程正好被选中唤醒。
        2)某个线程在当前条件对象上调用了signalAll()方法。
        3)其他线程调用此线程的interrput()方法,打断可此线程。
        调用await()方法之前。当前线程应该持有与Condition相关联的锁,否则会抛出IllegalMonitorException异常。
        一般来说,对await()方法的调用总是包含在一个循环结构中,并且await操作要放入try .... catch...语句块中。
         例如:
        while(条件){
            try{
                condition.await();
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
        2、signal()方法:
        signal()方法用于唤醒一个正在等待的线程,如果调用了此方法,则在当前条件对象上等待的线程中选择一线程进行唤醒,该线程在await()方法返回前仍需要重新获取对象锁,如果获取该锁程成功,则离开await()方法,否则将继续等待。
        3、signalAll()方法:
        signalAll()方法用于唤醒所有正在等待的线程。如果调用的此方法,则在当前条件对象等待的所有线程将被唤醒,被唤醒的线程将竞争获取锁,只有获得锁的线程才能离开await()方法,其他没有获取锁的线程则继续等待。

        Demo示例:
        使用条件对象实现多缓冲区生产消费者问题。
        分析:
        将多缓冲区生产消费问题中的wait().notifyAll()方法,替换为await()和signalAll()方法。只是替换时需要使用LocK对象,并且在该对象上定义相应的条件对象。

        public class CuddyHole{
            private int[] goods;//缓冲区
            private int front;//头指针
            private int rear;//尾指针
            private int nbuf;//缓冲区大小
            private int count;//缓冲区的数据的数量
            private Lock lock = new ReentrantLock();//
            Condition full = lock.newCondition();
            Condition empty = lock.newCondition();
            public CubbyHole(int nbuf){
                front = 0;
                rear = 0;
                count = 0;
                this.nbuf = nbuf;
                goods = new int[nbuf];
            }
            //取数据
            public int get(int id){
                lock.lock();
                try{
                    while(count<=0){
                        try{    
                            empty.await();
                        }catch(InterruptedException e){
                            e.printStackTrace();
                        }
                    }
                    front = (front+1)%nbuf;
                    System.out.println("第"+id+"号消费者拿走了数据"+goods[front]);
                    count--;
                    full.signal();
                    return goods[front];
                }finally{
                    lock.unlock();    
                }        
            }
            //存数据
            public void put(int value,int id){
                lock.lock();
                try{
                    while(count>=nbuf){
                        try{
                            full.await();
                        }catch(InterruptedException e){
                            e.printStackTrace();
                        }
                    }
                    rear = (rear+1)%nbuf;
                    goods[rear] = value;
                    System.out.println("第"+id+"号生产者生产了数据"+value);
                    count++;
                    empty.signal();
                }finally{
                    lock.unlock();
                }
            }
        }
    
        public class Consumer extends Thread{
            private CubbyHole cubbyHole;
            private int id;
            public Consumer(CubbyHole cubbyHole,int id ){
                this.cubbyHole = cubbyHole;
                this.id = id;
            }
            public void run(){
                for(int i=0;i<50;i++){
                    cubbyHole.get(id);
                }
            }
        }
        public class Producer extends Thread{
            private CubbyHole cubbyHole;
            private int id;
            public Producer( CubbyHole cubbyHole,int id){
                this.cubbyHole = cubbyHole;
                this.id = id ;
            }
            public void run(){
                for(int i=0;i<50;i++){
                    cubbyHole.put((int)(Math.random()*100),id);
                }
            }
        }
        public class Index{
            private static int np = 4;
            private static int nc = 4;
            private static int nbuf =10;
            public static void main(String [] args){
                CubbyHole cubbyHole = new CubbyHole(nbuf);
                Producer [] producer = new Producer[np];
                for(int i=0;i<producer.length;i++){
                    producer[i] = new Producer(cubbyHole,i+1);
                    producer[i].start();
                }
                Consumer [] consumer = new Consumer[nc];
                for(int i=0;i<consumer.length;i++){
                    consumer[i] = new Consumer(cubbyHole,i+1);
                    consumer[i].start();
                }
                try{
                    for(int i=0;i<np;i++){
                        producer[i].join();
                    }
                    for(int i=0;i<nc;i++){
                        consumer[i].join();
                    }
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
            }
        }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值