zoukankan      html  css  js  c++  java
  • 多线程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的情况了.

  • 相关阅读:
    python json 和 pickle的补充 hashlib configparser logging
    go 流程语句 if goto for swich
    go array slice map make new操作
    go 基础
    块级元素 行内元素 空元素
    咽炎就医用药(慢性肥厚性咽炎)
    春季感冒是风寒还是风热(转的文章)
    秋季感冒 咳嗽 怎么选药
    解决IE浏览器“无法显示此网页”的问题
    常用的 css 样式 记录
  • 原文地址:https://www.cnblogs.com/liaokailin/p/3796683.html
Copyright © 2011-2022 走看看