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

 更新时间:2020年05月25日 09:36:29   作者:斗战圣猿  
这篇文章主要介绍了Java判断线程池线程是否执行完毕,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

在使用多线程的时候有时候我们会使用 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("ËùÓеÄ×ÓÏ̶߳¼½áÊøÁË£¡");
    final long end = System.currentTimeMillis();
    System.out.println((end-start)/1000);
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • SpringBoot 跨域问题的解决方案

    SpringBoot 跨域问题的解决方案

    这篇文章主要介绍了SpringBoot 跨域问题的解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-06-06
  • Java的web开发中SSH框架的协作处理应用笔记

    Java的web开发中SSH框架的协作处理应用笔记

    这篇文章主要介绍了Java的web开发中SSH框架的协作处理应用笔记,SSH是指Struts和Spring以及Hibernate的框架搭配,需要的朋友可以参考下
    2015-12-12
  • Maven编译遇到Process terminated问题(四种情况全部解决)

    Maven编译遇到Process terminated问题(四种情况全部解决)

    这篇文章主要介绍了Maven编译遇到Process terminated问题(四种情况全部解决),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-07-07
  • Spring注解驱动之ApplicationListener用法解读

    Spring注解驱动之ApplicationListener用法解读

    这篇文章主要介绍了Spring注解驱动之ApplicationListener用法解读,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • Java8 Supplier接口和Consumer接口原理解析

    Java8 Supplier接口和Consumer接口原理解析

    这篇文章主要介绍了Java8 Supplier接口和Consumer接口原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • java-RGB调色面板的实现(事件监听器之匿名内部类)

    java-RGB调色面板的实现(事件监听器之匿名内部类)

    这篇文章主要介绍了java-RGB调色面板的实现(事件监听器之匿名内部类),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • Ajax登录验证实现代码

    Ajax登录验证实现代码

    这篇文章主要为大家详细介绍了jQuery+ajax实现用户登录验证,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • Java构造方法有什么作用?

    Java构造方法有什么作用?

    在本篇文章里小编给大家介绍了关于Java构造方法的作用以及相关的基础知识点,对此有需要的朋友们可以跟着学习下。
    2022-11-11
  • Java实时监控日志文件并输出的方法详解

    Java实时监控日志文件并输出的方法详解

    这篇文章主要给大家介绍了关于Java实时监控日志文件并输出的方法,文中通过示例代码介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面跟着小编一起来学习学习吧。
    2017-06-06
  • 浅析Java中关键词volatile底层的实现原理

    浅析Java中关键词volatile底层的实现原理

    在 Java 并发编程中,有 3 个最常用的关键字:synchronized、ReentrantLock 和 volatile,这篇文章主要来和大家聊聊volatile底层的实现原理,感兴趣的可以了解下
    2024-02-02

最新评论