zoukankan      html  css  js  c++  java
  • 多线程12-CyclicBarrier、CountDownLatch、Exchanger

    1.CyclicBarrier 

         表示大家彼此等待,大家集合好后才开始出发,分散活动后又在指定地点集合碰面

    package org.lkl.thead.foo;
    
    import java.util.concurrent.CyclicBarrier;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    /**
     * 表示大家彼此等待,大家集合好后才开始出发,分散活动后又在指定地点集合碰面
     */
    public class CyclicBarrierFoo {
         public static void main(String[] args) {
          ExecutorService threadPool =     Executors.newCachedThreadPool() ;
          
          final CyclicBarrier cyclicBarrier = new CyclicBarrier(3) ;  //表示有3个线程需要彼此等待  都执行到 cyclicBarrier.await() ;以后才继续执行 
          
          for(int i=1 ;i<=3 ;i++){
              Runnable r = new Runnable() {
                @Override
                public void run() {
                    
                    
                    try {
                        Thread.sleep((long)(Math.random()*10000));
                        System.out.println("线程" + Thread.currentThread().getName() + 
                                "即将到达集合地点1,当前已有" + (cyclicBarrier.getNumberWaiting()+1) + "个已经到达," + (cyclicBarrier.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));                        
                        
                        cyclicBarrier.await() ;  //类似于集合点
                        
                        
                        Thread.sleep((long)(Math.random()*10000));
                        System.out.println("线程" + Thread.currentThread().getName() + 
                                "即将到达集合地点2,当前已有" + (cyclicBarrier.getNumberWaiting()+1) + "个已经到达," + (cyclicBarrier.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));                        
                        
                        cyclicBarrier.await() ;  //类似于集合点
                        
                        Thread.sleep((long)(Math.random()*10000));
                        System.out.println("线程" + Thread.currentThread().getName() + 
                                "即将到达集合地点3,当前已有" + (cyclicBarrier.getNumberWaiting()+1) + "个已经到达," + (cyclicBarrier.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));                        
                        
                        cyclicBarrier.await() ;  //类似于集合点
                        
                        
                        
                    } catch (Exception e) {
                        e.printStackTrace();
                    } 
                }
            };
            threadPool.execute(r) ;
          }
        }
    }

    允许结果如下: 

    线程pool-1-thread-3即将到达集合地点1,当前已有1个已经到达,正在等候
    线程pool-1-thread-1即将到达集合地点1,当前已有2个已经到达,正在等候
    线程pool-1-thread-2即将到达集合地点1,当前已有3个已经到达,都到齐了,继续走啊
    线程pool-1-thread-3即将到达集合地点2,当前已有1个已经到达,正在等候
    线程pool-1-thread-1即将到达集合地点2,当前已有2个已经到达,正在等候
    线程pool-1-thread-2即将到达集合地点2,当前已有3个已经到达,都到齐了,继续走啊
    线程pool-1-thread-2即将到达集合地点3,当前已有1个已经到达,正在等候
    线程pool-1-thread-1即将到达集合地点3,当前已有2个已经到达,正在等候
    线程pool-1-thread-3即将到达集合地点3,当前已有3个已经到达,都到齐了,继续走啊

    2. CountdownLatchFoo

            犹如倒计时计数器,调用CountDownLatch对象的countDown方法就将计数器减1,当计数到达0时,则所有等待者或单个等待者开始执行

    可以实现一个人(也可以是多个人)等待其他所有人都来通知他,这犹如一个计划需要多个领导都签字后才能继续向下实施。还可以实现一个人通知多个人的效果,类似裁判一声口令,运动员同时开始奔跑

    package org.lkl.thead.foo;
    
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class CountdownLatchFoo {
      
        /**
         * 实现代码: 
         *  主线程发布命令  然后开启三个线程在等待主线程发布的命令 ,
         *  当子线程接收命令以后 传递一个回调的命令给主线程  然后主线程接收回调命令
         */
        
        
        public static void main(String[] args) {
            final CountDownLatch orderLatch = new CountDownLatch(1) ; //表示从1 开始倒计时
            final CountDownLatch answerLatch = new CountDownLatch(3) ; //表示从3开始倒计时
            
            ExecutorService threadPool = Executors.newCachedThreadPool() ;
            for(int i=1 ;i<=3 ;i++){
                Runnable runnable = new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("线程"+Thread.currentThread().getName()+"准备接收数据.");
                        try {
                            orderLatch.await() ; //表示等待主线程发布命令,没有接收到命令就会一致等待下去
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        
                        
                        System.out.println("线程"+Thread.currentThread().getName()+" 接收到命令 ");  //只有接收到命令 程序才会从await方法中执行下来
                        
                        //给主线程回调命令
                        
                        System.out.println("线程"+Thread.currentThread().getName()+" 准备向主线程回调. "); 
                        try {
                            Thread.sleep((long)(Math.random()*10000));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }    
                        answerLatch.countDown() ; //表示发布命令  从3开始倒计时   前期主线程会被answerLatch.await() 方法拦截下来 等待回调
                        
                        System.out.println("线程"+Thread.currentThread().getName()+" 已经向主线程回调. "); 
                        
                        
                    }
                };
                threadPool.execute(runnable) ;
            }
            
            //主线程
             
            try {
                Thread.sleep((long)(Math.random()*10000));
                System.out.println("主线程"+Thread.currentThread().getName()+"准备向三个子线程发送命令.");
                orderLatch.countDown() ; //向三个子线程发送命令
                System.out.println("主线程"+Thread.currentThread().getName()+"已经向三个子线程发送命令.");
                
                System.out.println("主线程"+Thread.currentThread().getName()+"等待三个子线程的回调.");
                answerLatch.await() ;
                
                System.out.println("主线程"+Thread.currentThread().getName()+"已经收到三个子线程的回调.");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

      运行结果: 

    线程pool-1-thread-1准备接收数据.
    线程pool-1-thread-2准备接收数据.
    线程pool-1-thread-3准备接收数据.
    主线程main准备向三个子线程发送命令.
    线程pool-1-thread-2 接收到命令 
    线程pool-1-thread-2 准备向主线程回调. 
    主线程main已经向三个子线程发送命令.
    主线程main等待三个子线程的回调.
    线程pool-1-thread-3 接收到命令 
    线程pool-1-thread-3 准备向主线程回调. 
    线程pool-1-thread-1 接收到命令 
    线程pool-1-thread-1 准备向主线程回调. 
    线程pool-1-thread-1 已经向主线程回调. 
    线程pool-1-thread-2 已经向主线程回调. 
    线程pool-1-thread-3 已经向主线程回调. 
    主线程main已经收到三个子线程的回调.

    3. Exchanger

    用于实现两个人之间的数据交换,每个人在完成一定的事务后想与对方交换数据,第一个先拿出数据的人将一直等待第二个人拿着数据到来时,才能彼此交换数据

    package org.lkl.thead.foo;
    
    import java.util.concurrent.Exchanger;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class ExchangerFoo {
    
        public static void main(String[] args) {
         ExecutorService threadPool =    Executors.newCachedThreadPool() ;
         final Exchanger<String> change = new Exchanger<String>() ;
         threadPool.execute(new Runnable() {
            
            @Override
            public void run() {
                try {
                    String myData = "zhangsan" ;
                    System.out.println("线程" + Thread.currentThread().getName() + 
                            "正在把数据" + myData +"换出去");
                    String mychange = change.exchange(myData) ;
                    Thread.sleep((long)(Math.random()*10000));
                    System.out.println("线程" + Thread.currentThread().getName() + 
                            "换回来的数据为" + mychange);
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                
            }
        }) ;
         
         
         threadPool.execute(new Runnable() {
             
             @Override
             public void run() {
                 try {
                     String myData = "lisi" ;
                     System.out.println("线程" + Thread.currentThread().getName() + 
                             "正在把数据" + myData +"换出去");
                     String mychange = change.exchange(myData) ;
                     Thread.sleep((long)(Math.random()*10000));
                     System.out.println("线程" + Thread.currentThread().getName() + 
                             "换回来的数据为" + mychange);
                 } catch (Exception e) {
                     // TODO Auto-generated catch block
                     e.printStackTrace();
                 }
                 
             }
         }) ;
         
         
        }
    }

    运行结果:

    线程pool-1-thread-2正在把数据lisi换出去
    线程pool-1-thread-1正在把数据zhangsan换出去
    线程pool-1-thread-2换回来的数据为zhangsan
    线程pool-1-thread-1换回来的数据为lisi
  • 相关阅读:
    vim使用基础
    linux基本命令随笔
    linux学习笔记
    中台建设随笔
    数据密集型系统响应优化
    TCP断开连接的问题
    多渠道接入系统总结
    关于实践的认识
    博客说明
    python下载图片的问题思考
  • 原文地址:https://www.cnblogs.com/liaokailin/p/3797101.html
Copyright © 2011-2022 走看看