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

  • 相关阅读:
    Java-GZIPOutputStream踩坑
    Redis事务
    Netty实现简单群聊
    SpringMVC请求参数解析
    Netty实现WebSocket
    SpringBoot项目war包部署
    NIO实现群聊
    SpringMVC请求映射handler源码解读
    SpringMVC自定义兼容性HandlerMapping
    spring boot自定义类配置绑定在配置文件中自动提示
  • 原文地址:https://www.cnblogs.com/liaokailin/p/3796683.html
Copyright © 2011-2022 走看看