Condition接口的用法和示例

mac2025-07-22  4

条件变量:线程进入临界区域后,往往需要等待满足某个条件才能继续执行。例如,消费者需要等待缓冲区有产品后才能消费,用户只有在银行账户上有金额的时候能能取款等。         在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)