欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

线程的join方法和countdownlatch类

程序员文章站 2022-04-03 13:37:35
...

线程的join方法和countdownlatch

线程之间的状态有5种初始、就绪、运行、阻塞、死亡,大家应该都知道,线程在由运行态到阻塞态时有一种方法joinJoin的功能和CountDownLatch类似,可以让所有子线程跑完再执行主线程。下面举例子说明两个的用法

1.线程的join方法,控制执行情况,实现主线程等待子线程。

我们可以拿Dota游戏来举例,在我们玩的时候可以进行单挑(Solo),玩过的应该不陌生,游戏我们认定为主线程,自己和对方定义为子线程,自己和对方的准备也就是加入AB队伍中,加入队伍我们认定是子线程的任务。只有当己方和对方都准备好(进入各自队伍),游戏就会自动开始(对战平台自己触发的)

publicclass ThreadJoinShow {

   privateclass ASubThread implements Runnable{

      private String name;

      public ASubThread(String name) {

         this.name = name;

      }

     

      @Override

      publicvoid run() {

         System.out.println(name+"======正在加入游戏===");

         try {

            Thread.sleep(3000);

         } catch (InterruptedException e) {

            e.printStackTrace();

         }

         System.out.println(name+"======准备好了===");

      }

   }

  

   privateclass BSubThread implements Runnable{

      private String name;

      public BSubThread(String name) {

         this.name = name;

      }

     

      @Override

      publicvoid run() {

         System.out.println(name+"======正在加入游戏===");

         try {

            Thread.sleep(3000);

         } catch (InterruptedException e) {

            e.printStackTrace();

         }

         System.out.println(name+"======准备好了===");

      }

   }

  

   @Test

   publicvoid testNoJoin() throws InterruptedException {

      System.out.println("魔兽初始界面加载请选择阵营====start");

      ASubThread asub = new ASubThread("天灾方选手A");

      BSubThread bsub = new BSubThread("近卫方选手B");

     

      Thread at = new Thread(asub);

      Thread bt = new Thread(bsub);

     

      at.start();

      bt.start();

      System.out.println("魔兽争霸之Dota====进度条走完===进入游戏===end");

      Thread.sleep(10000);//主线程暂停10s是为了防止主线程结束子线程也会跟着结束

   }

  

   @Test

   publicvoid testJoin() throws InterruptedException {

      System.out.println("Join版魔兽初始界面加载请选择阵营====start");

      ASubThread asub = new ASubThread("Join===天灾方选手A");

      BSubThread bsub = new BSubThread("Join===近卫方选手B");

     

      Thread at = new Thread(asub);

      Thread bt = new Thread(bsub);

     

      at.start();

      bt.start();

     

      try {

         at.join();

         bt.join();

      } catch (InterruptedException e) {

         e.printStackTrace();

      }

     

      System.out.println("Join版魔兽争霸之Dota====进度条走完===进入游戏===end");

      Thread.sleep(10000);//主线程暂停10s是为了防止主线程结束子线程也会跟着结束

   }

}

 

执行测试方法console控台打印日志分别如下:

魔兽初始界面加载请选择阵营====start

魔兽争霸之Dota====进度条走完===进入游戏===end

天灾方选手A======正在加入游戏===

近卫方选手B======正在加入游戏===

天灾方选手A======准备好了===

近卫方选手B======准备好了===

 

Join版魔兽初始界面加载请选择阵营====start

Join===天灾方选手A======正在加入游戏===

Join===近卫方选手B======正在加入游戏===

Join===天灾方选手A======准备好了===

Join===近卫方选手B======准备好了===

Join版魔兽争霸之Dota====进度条走完===进入游戏===end

 

由日志可以发现,用了join方法后,主线程会等待子线程执行完,所以正常的游戏流程应该用join版,只有大家都准备好了,才能进入游戏。

 

 

2.CountDownLatch类也可以实现上述的功能,就是等所有子任务都跑完了,主线程再往下执行。

CountDownLatch有两个方法是我们常用的:await();countDown();await()函数用于阻塞当前线程直到CountDownLatch的计数值变为0countDown()方法用于将当前CountDownLatch的计数值减1。举个例子,假设有个女子组合TF girls要参加中戏的艺考,三个人有表演唱歌有表演朗诵有表演舞蹈,只有都通过了,才能拿到中戏的录取通知书,代码如下:                                                                                         public class ThreadCountDownLatchShow {

  

   class SingSongTask implements Runnable{

 

      private CountDownLatch countDownLatch;

      public SingSongTask(CountDownLatch countDownLatch) {

         this.countDownLatch = countDownLatch;

      }

     

      @Override

      publicvoid run() {

         try {

            System.out.println("===A表演唱歌的===start");

            Thread.sleep(3000);

            System.out.println("===A表演唱歌的==表演结束==end");

            countDownLatch.countDown();

         } catch (InterruptedException e) {

            e.printStackTrace();

         }

      }

     

   }

  

   class ReadPoetryTask implements Runnable{

 

      private CountDownLatch countDownLatch;

     

      public ReadPoetryTask(CountDownLatch countDownLatch) {

         this.countDownLatch = countDownLatch;

      }

     

      @Override

      publicvoid run() {

         try {

            System.out.println("===B表演朗读的===start");

            Thread.sleep(6000);

            System.out.println("===B表演朗读的==表演结束==end");

            countDownLatch.countDown();

         } catch (InterruptedException e) {

            e.printStackTrace();

         }

      }

     

   }

  

   class DanceTask implements Runnable{

 

      private CountDownLatch countDownLatch;

     

      public DanceTask(CountDownLatch countDownLatch) {

         this.countDownLatch = countDownLatch;

      }

     

      @Override

      publicvoid run() {

         try {

            System.out.println("===C表演跳舞的===start");

            Thread.sleep(5000);

            System.out.println("===C表演跳舞的==表演结束==end");

            countDownLatch.countDown();

         } catch (InterruptedException e) {

            e.printStackTrace();

         }

      }

     

   }

  

   @Test

   publicvoid testGetZhongxiNotice() throws InterruptedException {

      System.out.println("===TF girls参加中戏考试===");

      CountDownLatch countDownLatch = new CountDownLatch(3);

     

      ExecutorService proctorExec = Executors.newFixedThreadPool(3);

      proctorExec.execute(new SingSongTask(countDownLatch));

      proctorExec.execute(new ReadPoetryTask(countDownLatch));

      proctorExec.execute(new DanceTask(countDownLatch));

      countDownLatch.await();

      proctorExec.shutdown();

      System.out.println("===TF girls参加中戏考试===考试结束===通过===发录取通知书==");

     

   }

}

执行测试方法console控台打印日志分别如下:

===TF girls参加中戏考试===

===A表演唱歌的===start

===B表演朗读的===start

===C表演跳舞的===start

===A表演唱歌的==表演结束==end

===C表演跳舞的==表演结束==end

===B表演朗读的==表演结束==end

===TF girls参加中戏考试===考试结束===通过===发录取通知书==