同步器

≡放荡痞女 提交于 2019-11-30 11:59:20
版权声明:本文为博主转载文章
原文链接:https://blog.csdn.net/lixiaobuaa/article/details/78995572

线程之间相互合作时,需要用到同步器来完成同步,下面介绍几种常用同步器:

1.Semaphore(信号量)
信号量数量限制了访问资源的线程总数,线程请求会消耗一个信号量,当信号量为0时,新的线程会阻塞,直到有线程释放了一个信号量

线程类:

package Semaphore;

import java.util.concurrent.Semaphore;

public class SemaphoreThread extends Thread{

    Semaphore semaphore;
    public SemaphoreThread(Semaphore semaphore){
        this.semaphore = semaphore;
    }
    @Override
    public void run() {
        try {
            semaphore.acquire();
            System.out.println("一个线程正在执行");
            sleep(3000);
            System.out.println("一个线程结束运行");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        semaphore.release();
    }
}

    测试类:

    package Semaphore;
    
    import java.util.concurrent.Semaphore;
    
    public class MainClass {
        public static void main(String[] args) {
            Semaphore semaphore = new Semaphore(3);
            SemaphoreThread t1 = new SemaphoreThread(semaphore);
            SemaphoreThread t2 = new SemaphoreThread(semaphore);
            SemaphoreThread t3 = new SemaphoreThread(semaphore);
            SemaphoreThread t4 = new SemaphoreThread(semaphore);
            SemaphoreThread t5 = new SemaphoreThread(semaphore);
            SemaphoreThread t6 = new SemaphoreThread(semaphore);
    
            t1.start();
            t2.start();
            t3.start();
            t4.start();
            t5.start();
            t6.start();
        }
    }

      运行结果:

      一个线程正在执行
      一个线程正在执行
      一个线程正在执行
      一个线程结束运行
      一个线程结束运行
      一个线程正在执行
      一个线程正在执行
      一个线程结束运行
      一个线程正在执行
      一个线程结束运行
      一个线程结束运行
      一个线程结束运行
      
      Process finished with exit code 0

        可以看到,由于我们把信号量数量设置为3,所以最多只能有3个线程在同时执行

        2.CountDownLatch(倒计时门栓)
        每完成一次特定操作,倒计时减一,线程集需要等到倒计时为0时才可执行。注意倒计时门栓是一次性的,计数为0后就不能再用了

        线程类:

        package CountDownLatch;
        
        import java.util.concurrent.CountDownLatch;
        
        public class CountDownLatchThread extends Thread {
            CountDownLatch countDownLatch;
            public CountDownLatchThread(CountDownLatch countDownLatch){
                this.countDownLatch = countDownLatch;
            }
        
            @Override
            public void run() {
                System.out.println("一个线程正在等待");
                try {
                    countDownLatch.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("一个线程结束等待");
            }
        }
        

          测试类:

          package CountDownLatch;
          
          import java.util.concurrent.CountDownLatch;
          
          public class MainClass {
              public static void main(String[] args) {
                  CountDownLatch countDownLatch = new CountDownLatch(3);
                  CountDownLatchThread t1 = new CountDownLatchThread(countDownLatch);
                  CountDownLatchThread t2 = new CountDownLatchThread(countDownLatch);
                  CountDownLatchThread t3 = new CountDownLatchThread(countDownLatch);
                  t1.start();
                  t2.start();
                  t3.start();
                  try {
                      System.out.println("计数减一");
                      Thread.sleep(1000);
                      countDownLatch.countDown();
                      System.out.println("计数减一");
                      Thread.sleep(1000);
                      countDownLatch.countDown();
                      System.out.println("计数减一");
                      Thread.sleep(1000);
                      countDownLatch.countDown();
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
          }
          

            运行结果:

            计数减一
            一个线程正在等待
            一个线程正在等待
            一个线程正在等待
            计数减一
            计数减一
            一个线程结束等待
            一个线程结束等待
            一个线程结束等待
            
            Process finished with exit code 0

              可以看到,由于我们把计时器设置为3,所以需要经过三次计数减一操作之后,线程集才可执行

              3.CyclicBarrier(循环障栅)
              线程在障栅处等待,当等待线程凑够一定数量后,打开障栅,放行这些线程,并执行阶段处理方法,然后重新关闭障栅

              线程类:

              package CyclicBarrier;
              
              import java.util.concurrent.BrokenBarrierException;
              import java.util.concurrent.CyclicBarrier;
              
              public class CyclicBarrierThread extends Thread {
                  CyclicBarrier cyclicBarrier;
              
                  public CyclicBarrierThread(CyclicBarrier cyclicBarrier) {
                      this.cyclicBarrier = cyclicBarrier;
                  }
              
                  @Override
                  public void run() {
                      System.out.println("正在等待");
              
                      try {
                          cyclicBarrier.await();
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      } catch (BrokenBarrierException e) {
                          e.printStackTrace();
                      }
                      System.out.println("开始执行");
              
                  }
              }
              

                阶段处理方法:

                package CyclicBarrier;
                
                public class Deal implements Runnable {
                    @Override
                    public void run() {
                        System.out.println("打开障栅");
                    }
                }
                

                  测试类:

                  package CyclicBarrier;
                  
                  import java.util.concurrent.CyclicBarrier;
                  
                  public class MainClass {
                  
                  
                      public static void main(String[] args) {
                          CyclicBarrier cyclicBarrier = new CyclicBarrier(2, new Deal());
                          CyclicBarrierThread t1 = new CyclicBarrierThread(cyclicBarrier);
                          CyclicBarrierThread t2 = new CyclicBarrierThread(cyclicBarrier);
                          CyclicBarrierThread t3 = new CyclicBarrierThread(cyclicBarrier);
                          CyclicBarrierThread t4 = new CyclicBarrierThread(cyclicBarrier);
                          CyclicBarrierThread t5 = new CyclicBarrierThread(cyclicBarrier);
                  
                          try {
                              t1.start();
                              Thread.sleep(2000);
                              t2.start();
                              Thread.sleep(2000);
                              t3.start();
                              Thread.sleep(2000);
                              t4.start();
                              Thread.sleep(2000);
                              t5.start();
                          } catch (InterruptedException e) {
                              e.printStackTrace();
                          }
                  
                      }
                  }
                  

                    运行结果:

                    正在等待
                    正在等待
                    打开障栅
                    开始执行
                    开始执行
                    正在等待
                    正在等待
                    打开障栅
                    开始执行
                    开始执行
                    正在等待

                      可以看到,由于我们把障栅大小设置为2,所以当等待线程到达2个时就打开障栅放行。由于我们只有5个线程,所以最后一个线程会一直在障栅处等待

                      4.Phaser(阶段器)
                      在循环障栅的基础上增加了控制器,可以在循环若干个阶段后拆除障栅。线程需要注册阶段器,当请求等待线程数等于注册线程数时,打开障栅,执行阶段处理方法,阶段处理方法返回true时拆除障栅。

                      线程类1:

                      package Phaser;
                      
                      import java.util.concurrent.Phaser;
                      
                      public class Thread1 extends Thread {
                          Phaser phaser;
                      
                          public Thread1(Phaser phaser) {
                              this.phaser = phaser;
                              phaser.register();
                          }
                      
                          @Override
                          public void run() {
                              System.out.println("等待中");
                              phaser.arriveAndAwaitAdvance();
                              System.out.println("等待中");
                              phaser.arriveAndAwaitAdvance();
                              System.out.println("注销");
                              phaser.arriveAndDeregister();
                          }
                      }

                        线程类2:

                        package Phaser;
                        
                        import java.util.concurrent.Phaser;
                        
                        public class Thread2 extends Thread {
                            Phaser phaser;
                        
                            public Thread2(Phaser phaser) {
                                this.phaser = phaser;
                                phaser.register();
                            }
                        
                            @Override
                            public void run() {
                                System.out.println("等待中");
                                phaser.arriveAndAwaitAdvance();
                                System.out.println("等待中");
                                phaser.arriveAndAwaitAdvance();
                                System.out.println("等待中");
                                phaser.arriveAndAwaitAdvance();
                                System.out.println("注销");
                                phaser.arriveAndDeregister();
                            }
                        }

                          测试类:

                          package Phaser;
                          
                          import java.util.concurrent.Phaser;
                          
                          public class MainClass {
                              public static void main(String[] args) {
                                  Phaser phaser = new Phaser() {
                                      @Override
                                      protected boolean onAdvance(int phase, int registeredParties) {
                                          try {
                                              System.out.println("一个阶段完成,注册线程数量:" + registeredParties + ",第" + phase + "阶段");
                                              Thread.sleep(2000);
                                          } catch (InterruptedException e) {
                                              e.printStackTrace();
                                          }
                                          return registeredParties == 1;
                                      }
                                  };
                          
                                  Thread1 t1 = new Thread1(phaser);
                                  Thread2 t2 = new Thread2(phaser);
                          
                                  t1.start();
                                  t2.start();
                              }
                          }
                          

                            运行结果:

                            等待中
                            等待中
                            一个阶段完成,注册线程数量:2,第0阶段
                            等待中
                            等待中
                            一个阶段完成,注册线程数量:2,第1阶段
                            注销
                            等待中
                            一个阶段完成,注册线程数量:1,第2阶段
                            注销
                            
                            Process finished with exit code 0

                              可以看到只有等待线程数目等于注册线程数目时,才会打开障栅,完成一个阶段。由于我们的设置是当注册线程数为1时拆除障栅,所以第2阶段完成后就拆除了障栅,不会再有第3阶段

                              5.Exchanger(交换器)
                              两个线程之间交换数据,注意必须成对线程才可交换,如果有单个线程无法成对就会一直阻塞

                              线程一:

                              package Exchanger;
                              
                              import java.util.concurrent.Exchanger;
                              
                              public class Thread1 extends Thread {
                                  Exchanger<String> exchanger;
                                  public Thread1(Exchanger<String> exchanger){
                                      this.exchanger = exchanger;
                                  }
                              
                                  @Override
                                  public void run() {
                                      System.out.println("线程1写入数据1");
                                      try {
                                          System.out.println("线程1获得数据:"+exchanger.exchange("1"));
                                      } catch (InterruptedException e) {
                                          e.printStackTrace();
                                      }
                                  }
                              }
                              

                                线程二:

                                package Exchanger;
                                
                                import java.util.concurrent.Exchanger;
                                
                                public class Thread2 extends Thread {
                                    Exchanger<String> exchanger;
                                    public Thread2(Exchanger<String> exchanger){
                                        this.exchanger = exchanger;
                                    }
                                
                                    @Override
                                    public void run() {
                                        System.out.println("线程2写入数据2");
                                        try {
                                            sleep(2000);
                                            System.out.println("线程2获得数据:"+exchanger.exchange("2"));
                                        } catch (InterruptedException e) {
                                            e.printStackTrace();
                                        }
                                    }
                                }
                                

                                  线程三:

                                  package Exchanger;
                                  
                                  import java.util.concurrent.Exchanger;
                                  
                                  public class Thread3 extends Thread {
                                      Exchanger<String> exchanger;
                                      public Thread3(Exchanger<String> exchanger){
                                          this.exchanger = exchanger;
                                      }
                                  
                                      @Override
                                      public void run() {
                                          System.out.println("线程3写入数据3");
                                          try {
                                              System.out.println("线程3获得数据:"+exchanger.exchange("3"));
                                          } catch (InterruptedException e) {
                                              e.printStackTrace();
                                          }
                                      }
                                  }
                                  

                                    测试类:

                                    package Exchanger;
                                    
                                    import java.util.concurrent.Exchanger;
                                    
                                    public class MainClass {
                                        public static void main(String[] args) {
                                            Exchanger<String> exchanger = new Exchanger<String>();
                                    
                                            Thread1 t1 = new Thread1(exchanger);
                                            Thread2 t2 = new Thread2(exchanger);
                                            Thread3 t3 = new Thread3(exchanger);
                                    
                                            t1.start();
                                            t2.start();
                                            t3.start();
                                        }
                                    }
                                    

                                      运行结果:

                                      线程1写入数据1
                                      线程2写入数据2
                                      线程3写入数据3
                                      线程3获得数据:1
                                      线程1获得数据:3

                                        由于我们人为让线程2休眠了2秒,所以线程1和线程3先准备好并交换了数据,线程2就一直处于阻塞状态

                                        6.SynchronousQueue(同步队列)
                                        当一个线程调用put方法时,它会一直阻塞直到另一个线程调用take方法,与Exchanger类似,但Exchanger数据双向传递,SynchronousQueue数据单向传递

                                        线程之间相互合作时,需要用到同步器来完成同步,下面介绍几种常用同步器:

                                        易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
                                        该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!