1.目标
假定有一个绑定的缓冲区,它支持 put 和 take 方法。如果试图在空的缓冲区上执行 take 操作,则在某一个项变得可用之前,线程将一直阻塞;如果试图在满的缓冲区上执行 put
操作,则在有空间变得可用之前,线程将一直阻塞。我们喜欢在单独的等待 set 中保存 put 线程和 take 线程,这样就可以在缓冲区中的项或空间变得可用时利用最佳规划,一次只通知一个线程
2.代码实现
package org.lkl.thead.foo02; import java.util.Random; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class BoundedBufferFoo { static class BoundedBuffer{ Lock lock = new ReentrantLock() ; Condition notFull = lock.newCondition() ; Condition notEmpty = lock.newCondition() ; Object[] queue = new Object[10] ; int putptr=0,takeptr=0,count=0 ; public void put(Object x ){ lock.lock() ; try { while(count == queue.length){ // 队列满 等待take取走数据 notFull.await() ; } //放入数据 queue[putptr] = x ; if(++putptr==queue.length) putptr = 0 ; //归0 ++count ; //放入以后 提醒可以take notEmpty.signal() ; } catch (Exception e) { }finally{ lock.unlock() ; } } public Object take(){ lock.lock() ; try { //为空 则等待 while(count==0){ notEmpty.await() ; } Object x = queue[takeptr] ; if(++takeptr==queue.length) takeptr = 0 ; --count ; notFull.signal() ; //提醒可以再put return x ; } catch (Exception e) { }finally{ lock.unlock() ; } return null ; } } public static void main(String[] args) { final BoundedBuffer buffer = new BoundedBuffer() ; new Thread(new Runnable() { @Override public void run() { while(true){ try { Thread.sleep(500) ; } catch (InterruptedException e) { e.printStackTrace(); } int putstr = new Random().nextInt(10000) ; buffer.put(putstr) ; System.out.println("put " + putstr); } } }).start() ; new Thread(new Runnable() { @Override public void run() { while(true){ try { Thread.sleep(2000) ; } catch (InterruptedException e) { e.printStackTrace(); } Object o = buffer.take() ; System.out.println("get " + o); } } }).start() ; } }
注意 :上面的代码来自JDK API 中Condition的示例代码 在实际的开发中没有必要自己去实现这样子的代码 主要是体现这种思想 在ArrayBlockingQueue类中提供了类似的功能
在take 方法中有个地方要注意: lock.unlock 是在return x 之后执行的,调用return x 之后, take方法的返回值确定下来了但是真个方法并没有结束,finally中一定会执行,千万不要认为这个take
方法没有释放锁.
看下面的一个例子:
public static void main(String[] args) { System.out.println(test()); } public static int test() { int x = 0 ; try { x = 23 ; System.out.println("before return "); return x; } catch (Exception e) { }finally{ x = 30 ; System.out.println("finally"); } return x ; }
执行结果如下:
before return finally 23
如果把代码给修改一下:
public static void main(String[] args) { System.out.println(test()); } public static int test() { int x = 0 ; try { x = 23 ; System.out.println("before return "); //return x; } catch (Exception e) { }finally{ x = 30 ; System.out.println("finally"); } return x ; }
执行的结果:
before return finally 30
通过上面的比较很容易理解前面说的take的情况了.