多线程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 
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的情况了.

 

 

 

 

 

 

 

 

 

 

多线程10-模拟缓冲区,布布扣,bubuko.com

多线程10-模拟缓冲区

上一篇:windows cmd 指令


下一篇:C++类基本--随笔