【多线程研究专题二】【Condtion使用实例】ArrayBlockingQueue解析

xiaoxiao2021-02-28  111

在研究Condition时,发现它的API提供了BoudedBuffer实现,并指出 ArrayBlockingQueue就是一个BoudedBuffer的高阶实现。 因此深入研究了下BoudedBuffer,其核心思想是: 1. 使用一个循环数组 2. 定义一个Count,作为put和take的次数差值约束,并使得put次数-take次数的差值为 0 - Capacity。达到边界的线程,就进入waiting状态,这样的目的是避免数组坐标越界。 正文: Condtion的API有如下例子,实现了BoundedBuffer,并指出,ArrayBlockingQueue就是这样实现的,所以没必要自己实现,直接用ArrayBlockingQueue即可。 A  Condition instance is intrinsically bound to a lock. To obtain a  Condition instance for a particular  Lock instance use its  newCondition() method.

As an example, suppose we have a bounded buffer which supports put and take methods. If a take is attempted on an empty buffer, then the thread will block until an item becomes available; if a put is attempted on a full buffer, then the thread will block until a space becomes available. We would like to keep waiting put threads and take threads in separate wait-sets so that we can use the optimization of only notifying a single thread at a time when items or spaces become available in the buffer. This can be achieved using two Condition instances.

class BoundedBuffer { final Lock lock = new ReentrantLock(); final Condition notFull = lock.newCondition(); final Condition notEmpty = lock.newCondition(); final Object[] items = new Object[100]; int putptr, takeptr, count; public void put(Object x) throws InterruptedException { lock.lock(); try { while (count == items.length) notFull.await(); items[putptr] = x; if (++putptr == items.length) putptr = 0; ++count; notEmpty.signal(); } finally { lock.unlock(); } } public Object take() throws InterruptedException { lock.lock(); try { while (count == 0) notEmpty.await(); Object x = items[takeptr]; if (++takeptr == items.length) takeptr = 0; --count; notFull.signal(); return x; } finally { lock.unlock(); } } } (The ArrayBlockingQueue class provides this functionality, so there is no reason to implement this sample usage class.) package  condtion; import  java.util.concurrent.ArrayBlockingQueue; import  java.util.concurrent.locks.Condition; import  java.util.concurrent.locks.Lock; import  java.util.concurrent.locks.ReentrantLock; public   class  ArrayBlockingQueueTest {        //ArrayBlockingQueue 和 BouderyBuffer 的循环数组使用同样的容量        static   final   int   Capacity  = 5;               public   static   void  main(String[]  args ) {              // ArrayBlockingQueue的主要框架就是BoudedBuffer。             ArrayBlockingQueue  blockQueue1  =  new  ArrayBlockingQueue<>( Capacity );              // 看看BoundedBuffer的执行效果             BoundedBuffer  blockQueue2  =  new  BoundedBuffer();              // 在这个例子,入参可以替换,只是循环数组的容量不一样,效果有所不同              // blockQueue1/blockQueue2             Runnable  taskPut  =  new  RunnablePut( blockQueue2 );             Runnable  taskTake  =  new  RunnableTake( blockQueue2 );              new  Thread( taskPut ).start();              new  Thread( taskTake ).start();       }        static   class  RunnableTake<T>  implements  Runnable {             T  queue ;              public  RunnableTake(T  blockQueue2 ) {                    queue  =  blockQueue2 ;             }              @Override              public   void  run() {                    for  ( int   i  = 0;  i  < 100;  i ++) {                          try  {                                int   result  = 0;                                if  ( queue   instanceof  BoundedBuffer) {                                      result  = ( int ) ((BoundedBuffer)  queue ).take();                               }  else  {                                      result  = ( int ) ((ArrayBlockingQueue queue ).take();                               }                               System. out .printf( "take result = %d\r\n" result );                         }  catch  (InterruptedException  e ) {                                //  TODO  Auto-generated catch block                                e .printStackTrace();                         }                   }             }       }        static   class  RunnablePut<T>  implements  Runnable {             T  queue ;              public  RunnablePut(T  blockQueue2 ) {                    queue  =  blockQueue2 ;             }              @Override              public   void  run() {                    for  ( int   i  = 0;  i  < 100;  i ++) {                          try  {                               System. out .printf( "goint to put : %d\r\n" i );                                                               if  ( queue   instanceof  BoundedBuffer) {                                     ((BoundedBuffer)  queue ).put( i );                               }  else  {                                     ((ArrayBlockingQueue)  queue ).put( i );                               }                         }  catch  (InterruptedException  e ) {                                //  TODO  Auto-generated catch block                                e .printStackTrace();                         }                   }             }       }        static   class  BoundedBuffer {              final  Lock  lock  =  new  ReentrantLock();              final  Condition  notFull  =  lock .newCondition();              final  Condition  notEmpty  =  lock .newCondition();              final  Object[]  items  =  new  Object[ Capacity ];                           //ptr作用:读写数组的数据。疑问:如何确保数据不被重复读取?              int   putptr takeptr ;                           /* count作用:          * 前提说明: items是一个循环数组,默认容量是5,实例从Object[0] - Object[4]。          * 从而限定了put和take的操作的次数差值只能为[0-5],避免xxxptr越界操作。          *                 * count == 0. 说明take和put的操作次数相等          * count == 5. 说明put的次数等于5。这是循环数组items[5]的极限.          * count > 5 . 说明put的操作次数比take次数超出5次,而循环数组大小是5,说明有数据还没来得及被take就被覆盖了。                * count < 0 . 说明take操作比put还多,表示take获取到了还没put的数据。          * 因为>5和<0的情况是不允许的,因此count的边界是0-5.在这两个值出现的时候,进行Condition条件等待。                             */              int   count ;              public   void  put(Object  x throws  InterruptedException {                    lock .lock();                    try  {                          while  ( count  ==  items . length ) {                               System. out .println( "Queue is Fullded" );                                notFull .await();                         }                          items [ putptr ] =  x ;                                                   if  (++ putptr  ==  items . length ) {                                putptr  = 0;                         }                         ++ count ;                          notEmpty .signal();                   }  finally  {                          lock .unlock();                   }             }              public  Object take()  throws  InterruptedException {                    lock .lock();                    try  {                          while  ( count  == 0) {                               System. out .println( "Queue is Empty" );                                notEmpty .await();                         }                         Object  x  =  items [ takeptr ];                          if  (++ takeptr  ==  items . length ) {                                takeptr  = 0;                         }                         -- count ;                          notFull .signal();                          return   x ;                   }  finally  {                          lock .unlock();                   }             }       } }
转载请注明原文地址: https://www.6miu.com/read-85857.html

最新回复(0)