Java判断线程池线程是否执行完毕

作者:斗战圣猿 时间:2023-10-18 12:09:29 

在使用多线程的时候有时候我们会使用 java.util.concurrent.Executors的线程池,当多个线程异步执行的时候,我们往往不好判断是否线程池中所有的子线程都已经执行完毕,但有时候这种判断却很有用,例如我有个方法的功能是往一个文件异步地写入内容,我需要在所有的子线程写入完毕后在文件末尾写“---END---”及关闭文件流等,这个时候我就需要某个标志位可以告诉我是否线程池中所有的子线程都已经执行完毕,我使用这种方式来判断。


public class MySemaphore {

public static void main(String[] args) throws IOException, InterruptedException {
   final File stream = new File("c:\\temp\\stonefeng\\stream.txt");
   final OutputStream os = new FileOutputStream(stream);
   final OutputStreamWriter writer = new OutputStreamWriter(os);
   final Semaphore semaphore = new Semaphore(10);
   ExecutorService exec = Executors.newCachedThreadPool();

final long start = System.currentTimeMillis();
   for (int i = 0; i < 10000000; i++) {
     final int num = i;
     Runnable task = new Runnable() {
       @Override
       public void run() {
         try {
           semaphore.acquire();
           writer.write(String.valueOf(num)+"\n");
           semaphore.release();
         } catch (IOException e) {
           e.printStackTrace();
         } catch (InterruptedException e) {
           e.printStackTrace();
         }
       }
     };
     exec.submit(task);
   }
   exec.shutdown();
   while(true){
     if(exec.isTerminated()){
       writer.write("---END---\n");
       writer.close();
       System.out.println("所有的子线程都结束了!");
       break;
     }
     Thread.sleep(1000);
   }
   final long end = System.currentTimeMillis();
   System.out.println((end-start)/1000);
 }
}

当调用ExecutorService.shutdown方法的时候,线程池不再接收任何新任务,但此时线程池并不会立刻退出,直到添加到线程池中的任务都已经处理完成,才会退出。在调用shutdown方法后我们可以在一个死循环里面用isTerminated方法判断是否线程池中的所有线程已经执行完毕,如果子线程都结束了,我们就可以做关闭流等后续操作了。

判断线程池中的线程是否全部执行完毕的另外一种解决方案则是使用闭锁(CountDownLatch)来实现,CountDownLatch是一种灵活的闭锁实现,它可以使一个或多个线程等待一组事件发生。闭锁状态包括一个计数器,该计数器被初始化为一个正数,表示需要等待的事件数量。countDown方法递减计数器,表示有一个事件已经发生了,而await方法等待计数器达到零,即表示需要等待的事情都已经发生。可以使用闭锁来这样设计程序达到目的:


public class CountDownLatchApproach {
 public static void main(String[] args) throws IOException, InterruptedException {
   final int nThreads = 10;
   final CountDownLatch endGate = new CountDownLatch(nThreads);
   final File stream = new File("c:\\temp\\stonefeng\\stream.txt");
   final OutputStream os = new FileOutputStream(stream);
   final OutputStreamWriter writer = new OutputStreamWriter(os);
   ExecutorService exec = Executors.newCachedThreadPool();
   for (int i = 0; i < nThreads; i++) {
     final int num = i;
     Runnable task = new Runnable() {
       @Override
       public void run() {
         try {
           writer.write(String.valueOf(num)+"\n");
         } catch (IOException e) {
           e.printStackTrace();
         } finally {
           endGate.countDown();
         }
       }
     };
     exec.submit(task);
   }
   endGate.await();
   writer.write("---END---\n");
   writer.close();
 }
}

这种解决方案虽然可以达到目的但是性能差到没朋友,我更倾向于使用第一种方案。

现在我们有了更优雅的第三种方案,它的执行性能也不错。


public class MySemaphore {

public static void main(String[] args) throws IOException, InterruptedException {
   final File stream = new File("c:\\temp\\stonefeng\\stream.txt");
   final OutputStream os = new FileOutputStream(stream);
   final OutputStreamWriter writer = new OutputStreamWriter(os);
   final Semaphore semaphore = new Semaphore(10);
   ExecutorService exec = Executors.newCachedThreadPool();

final long start = System.currentTimeMillis();
   for (int i = 0; i < 10000000; i++) {
     final int num = i;
     Runnable task = new Runnable() {
       @Override
       public void run() {
         try {
           semaphore.acquire();
           writer.write(String.valueOf(num)+"\n");
           semaphore.release();
         } catch (IOException e) {
           e.printStackTrace();
         } catch (InterruptedException e) {
           e.printStackTrace();
         }
       }
     };
     exec.submit(task);
   }
   exec.shutdown();
   exec.awaitTermination(1, TimeUnit.HOURS);
   writer.write("---END---\n");
   writer.close();
   System.out.println("&Euml;ù&Oacute;&ETH;&micro;&Auml;×&Oacute;&Iuml;&szlig;&sup3;&Igrave;&para;&frac14;&frac12;á&Ecirc;&oslash;&Aacute;&Euml;&pound;&iexcl;");
   final long end = System.currentTimeMillis();
   System.out.println((end-start)/1000);
 }
}

来源:https://www.cnblogs.com/zhangpeng8888/p/12702251.html

标签:Java,线程,池,执行
0
投稿

猜你喜欢

  • MyBatis-Plus工具使用之EntityWrapper解析

    2021-10-09 06:13:48
  • c#反射调用方法示例

    2022-07-14 15:28:40
  • java递归实现汉诺塔步骤介绍

    2022-03-03 09:44:17
  • 测试springboot项目出现Test Ignored的解决

    2022-06-25 08:37:02
  • 详解C# WebApi 接口测试工具:WebApiTestClient

    2022-05-15 07:58:44
  • WheelView实现上下滑动选择器

    2023-01-02 18:31:03
  • Android中CountDownTimer倒计时器用法实例

    2022-08-10 16:59:40
  • Android 8.0的缓存大小和缓存清理接口方法

    2023-11-09 16:47:06
  • FrameLayout和Fragment处理Android应用UI布局实例

    2021-07-05 15:27:09
  • Android开发之对话框案例详解(五种对话框)

    2021-08-07 11:37:47
  • java图形界面编程之模拟血压计

    2023-10-01 07:16:05
  • java取两个字符串的最大交集

    2021-07-30 17:23:08
  • Android使用 Coroutine + Retrofit打造简单的HTTP请求库

    2023-11-17 04:56:11
  • Java中HashMap与String字符串互转的问题解决

    2023-12-21 11:11:28
  • SpringCloud Gateway 路由配置定位原理分析

    2022-06-10 19:57:47
  • 深入解析Spring Boot 的SPI机制详情

    2021-07-09 04:26:49
  • Spring Boot2如何构建可部署的war包

    2023-11-29 06:40:59
  • springMVC实现文件上传和下载

    2023-04-17 16:39:07
  • 详解Kotlin:forEach也能break和continue

    2022-05-03 01:24:10
  • 使用java为pdf添加书签的方法(pdf书签制作)

    2022-03-07 14:59:11
  • asp之家 软件编程 m.aspxhome.com