首页 > 代码库 > 多线程10-模拟缓冲区

多线程10-模拟缓冲区

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 finally23

 

如果把代码给修改一下: 

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 finally30

 

 

通过上面的比较很容易理解前面说的take的情况了.