zoukankan      html  css  js  c++  java
  • CountDownLatch、CyclicBarrier、Semaphore、Exchanger

    CountDownLatch:

    允许N个线程等待其他线程完成执行。无法进行重复使用,只能用一次。

    比如有2个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了。

    public class Test {
    
         public static void main(String[] args) {    
    
             final CountDownLatch latch = new CountDownLatch(2);
    
              
    
             new Thread(){
    
                 public void run() {
    
                     try {
    
                         System.out.println("子线程"+Thread.currentThread().getName()+"正在执行");
    
                        Thread.sleep(3000);
    
                        System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕");
    
                        latch.countDown();
    
                    } catch (InterruptedException e) {
    
                        e.printStackTrace();
    
                    }
    
                 };
    
             }.start();
    
              
    
             new Thread(){
    
                 public void run() {
    
                     try {
    
                         System.out.println("子线程"+Thread.currentThread().getName()+"正在执行");
    
                         Thread.sleep(3000);
    
                         System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕");
    
                         latch.countDown();
    
                    } catch (InterruptedException e) {
    
                        e.printStackTrace();
    
                    }
    
                 };
    
             }.start();
    
              
    
             try {
    
                 System.out.println("等待2个子线程执行完毕...");
    
                latch.await();
    
                System.out.println("2个子线程已经执行完毕");
    
                System.out.println("继续执行主线程");
    
            } catch (InterruptedException e) {
    
                e.printStackTrace();
    
            }
    
         } 
    
    }
    线程Thread-0正在执行
    线程Thread-1正在执行
    等待2个子线程执行完毕...
    线程Thread-0执行完毕
    线程Thread-1执行完毕
    2个子线程已经执行完毕
    继续执行主线程

    CyclicBarrier

    实现让N个线程等待至某个状态(达到初始化数量值)之后再全部同时执行,并且要全部线程都执行cyclicBarrier.await();后才执行线程后续逻辑。

    在初次的4个线程越过barrier状态后,又可以用来进行新一轮的使用,可重复使用。

    比如聚餐,一个人先到了就开始等待,又来一个。。直到全部人到期后,这时才能吃饭,全部吃完后由一个人去结账(runable),最后每个人去做自己的事情。

    public class Test {
    
        public static void main(String[] args) {
    
            int N = 4;
    
            CyclicBarrier barrier  = new CyclicBarrier(N);
    
            for(int i=0;i<N;i++)
    
                new Writer(barrier).start();
    
        } 
    
        static class Writer extends Thread{
    
            private CyclicBarrier cyclicBarrier;
    
            public Writer(CyclicBarrier cyclicBarrier) {
    
                this.cyclicBarrier = cyclicBarrier;
    
            }
    
     
    
            @Override
    
            public void run() {
    
                System.out.println("线程"+Thread.currentThread().getName()+"正在写入数据...");
    
                try {
    
                    Thread.sleep(5000);      //以睡眠来模拟写入数据操作
    
                    System.out.println("线程"+Thread.currentThread().getName()+"写入数据完毕,等待其他线程写入完毕");
    
                    cyclicBarrier.await();
    
                } catch (InterruptedException e) {
    
                    e.printStackTrace();
    
                }catch(BrokenBarrierException e){
    
                    e.printStackTrace();
    
                }
    
                System.out.println("所有线程写入完毕,继续处理其他任务...");
    
            }
    
        }
    
    }
    线程Thread-0正在写入数据...
    线程Thread-3正在写入数据...
    线程Thread-2正在写入数据...
    线程Thread-1正在写入数据...
    线程Thread-2写入数据完毕,等待其他线程写入完毕
    线程Thread-0写入数据完毕,等待其他线程写入完毕
    线程Thread-3写入数据完毕,等待其他线程写入完毕
    线程Thread-1写入数据完毕,等待其他线程写入完毕
    所有线程写入完毕,继续处理其他任务...
    所有线程写入完毕,继续处理其他任务...
    所有线程写入完毕,继续处理其他任务...
    所有线程写入完毕,继续处理其他任务...


      从上面输出结果可以看出,每个写入线程执行完写数据操作之后,就在等待其他线程写入操作完毕。

      当所有线程线程写入操作完毕之后,所有线程就继续进行后续的操作了。

    public class Test {
    
        public static void main(String[] args) {
    
            int N = 4;
    
            CyclicBarrier barrier  = new CyclicBarrier(N,new Runnable() {
    
                @Override
    
                public void run() {
    
                    System.out.println("当前线程"+Thread.currentThread().getName());    
    
                }
    
            });
    
             
    
            for(int i=0;i<N;i++)
    
                new Writer(barrier).start();
    
        } 
    
        static class Writer extends Thread{
    
            private CyclicBarrier cyclicBarrier;
    
            public Writer(CyclicBarrier cyclicBarrier) {
    
                this.cyclicBarrier = cyclicBarrier;
    
            }
    
     
    
            @Override
    
            public void run() {
    
                System.out.println("线程"+Thread.currentThread().getName()+"正在写入数据...");
    
                try {
    
                    Thread.sleep(5000);      //以睡眠来模拟写入数据操作
    
                    System.out.println("线程"+Thread.currentThread().getName()+"写入数据完毕,等待其他线程写入完毕");
    
                    cyclicBarrier.await();
    
                } catch (InterruptedException e) {
    
                    e.printStackTrace();
    
                }catch(BrokenBarrierException e){
    
                    e.printStackTrace();
    
                }
    
                System.out.println("所有线程写入完毕,继续处理其他任务...");
    
            }
    
        }
    
    }
    线程Thread-0正在写入数据...
    线程Thread-1正在写入数据...
    线程Thread-2正在写入数据...
    线程Thread-3正在写入数据...
    线程Thread-0写入数据完毕,等待其他线程写入完毕
    线程Thread-1写入数据完毕,等待其他线程写入完毕
    线程Thread-2写入数据完毕,等待其他线程写入完毕
    线程Thread-3写入数据完毕,等待其他线程写入完毕
    当前线程Thread-3
    所有线程写入完毕,继续处理其他任务...
    所有线程写入完毕,继续处理其他任务...
    所有线程写入完毕,继续处理其他任务...
    所有线程写入完毕,继续处理其他任务...

    从结果可以看出,当四个线程都到达barrier状态后,会从四个线程中选择一个线程去执行Runnable。

    Semaphore

    可以控同时访问的线程个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。

    假若一个工厂有5台机器,但是有8个工人,一台机器同时只能被一个工人使用,只有使用完了,其他工人才能继续使用。那么我们就可以通过Semaphore来实现:

    public class Test {
    
        public static void main(String[] args) {
    
            int N = 8;            //工人数
    
            Semaphore semaphore = new Semaphore(5); //机器数目
    
            for(int i=0;i<N;i++)
    
                new Worker(i,semaphore).start();
    
        } 
    
         
    
        static class Worker extends Thread{
    
            private int num;
    
            private Semaphore semaphore;
    
            public Worker(int num,Semaphore semaphore){
    
                this.num = num;
    
                this.semaphore = semaphore;
    
            }
    
             
    
            @Override
    
            public void run() {
    
                try {
    
                    semaphore.acquire();
    
                    System.out.println("工人"+this.num+"占用一个机器在生产...");
    
                    Thread.sleep(2000);
    
                    System.out.println("工人"+this.num+"释放出机器");
    
                    semaphore.release();            
    
                } catch (InterruptedException e) {
    
                    e.printStackTrace();
    
                }
    
            }
    
        }
    
    }
    工人0占用一个机器在生产...
    工人1占用一个机器在生产...
    工人2占用一个机器在生产...
    工人4占用一个机器在生产...
    工人5占用一个机器在生产...
    工人0释放出机器
    工人2释放出机器
    工人3占用一个机器在生产...
    工人7占用一个机器在生产...
    工人4释放出机器
    工人5释放出机器
    工人1释放出机器
    工人6占用一个机器在生产...
    工人3释放出机器
    工人7释放出机器
    工人6释放出机器

    下面对上面说的三个辅助类进行一个总结:

      1)CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同:

        CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行;

        而CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行;

        另外,CountDownLatch是不能够重用的,而CyclicBarrier是可以重用的。

      2)Semaphore其实和锁有点类似,它一般用于控制对某组资源的访问权限。

    Exchanger

    Exchanger可以在两个线程之间交换数据,只能是2个线程,他不支持更多的线程之间互换数据。

    当线程A调用Exchange对象的exchange()方法后,他会陷入阻塞状态,直到线程B也调用了exchange()方法,然后以线程安全的方式交换数据,之后线程A和B继续运行。

    public class ThreadLocalTest {  
      
        public static void main(String[] args) {  
            Exchanger<List<Integer>> exchanger = new Exchanger<>();  
            new Consumer(exchanger).start();  
            new Producer(exchanger).start();  
        }  
      
    }  
      
    class Producer extends Thread {  
        List<Integer> list = new ArrayList<>();  
        Exchanger<List<Integer>> exchanger = null;  
        public Producer(Exchanger<List<Integer>> exchanger) {  
            super();  
            this.exchanger = exchanger;  
        }  
        @Override  
        public void run() {  
            Random rand = new Random();  
            for(int i=0; i<10; i++) {  
                list.clear();  
                list.add(rand.nextInt(10000));  
                list.add(rand.nextInt(10000));  
                list.add(rand.nextInt(10000));  
                list.add(rand.nextInt(10000));  
                list.add(rand.nextInt(10000));  
                try {  
                    list = exchanger.exchange(list);  
                } catch (InterruptedException e) {  
                    // TODO Auto-generated catch block  
                    e.printStackTrace();  
                }  
            }  
        }  
    }  
      
    class Consumer extends Thread {  
        List<Integer> list = new ArrayList<>();  
        Exchanger<List<Integer>> exchanger = null;  
        public Consumer(Exchanger<List<Integer>> exchanger) {  
            super();  
            this.exchanger = exchanger;  
        }  
        @Override  
        public void run() {  
            for(int i=0; i<10; i++) {  
                try {  
                    list = exchanger.exchange(list);  
                } catch (InterruptedException e) {  
                    // TODO Auto-generated catch block  
                    e.printStackTrace();  
                }  
                System.out.print(list.get(0)+", ");  
                System.out.print(list.get(1)+", ");  
                System.out.print(list.get(2)+", ");  
                System.out.print(list.get(3)+", ");  
                System.out.println(list.get(4)+", ");  
            }  
        }  
    }  

    8041, 3278, 7654, 2981, 7529,
    7091, 4699, 3542, 9739, 3587,
    1981, 3427, 7698, 8519, 4319,
    2119, 8179, 4338, 7676, 2617,
    2772, 6843, 9765, 8948, 418,
    7433, 7846, 9442, 6114, 6475,
    9142, 4858, 6511, 6401, 9709,
    6466, 9250, 3018, 8256, 8771,
    80, 8762, 7367, 8664, 9053,
    8008, 5456, 2018, 9806, 8194,

     
  • 相关阅读:
    HDU 1022 Train Problem I
    HDU 1702 ACboy needs your help again!
    HDU 1294 Rooted Trees Problem
    HDU 1027 Ignatius and the Princess II
    HDU 3398 String
    HDU 1709 The Balance
    HDU 2152 Fruit
    HDU 1398 Square Coins
    HDU 3571 N-dimensional Sphere
    HDU 2451 Simple Addition Expression
  • 原文地址:https://www.cnblogs.com/wade-luffy/p/5769380.html
Copyright © 2011-2022 走看看