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("ËùÓеÄ×ÓÏ̶߳¼½áÊøÁË£¡");
final long end = System.currentTimeMillis();
System.out.println((end-start)/1000);
}
}
来源:https://www.cnblogs.com/zhangpeng8888/p/12702251.html
猜你喜欢
- Java与Oracle实现事务(JDBC事务)实例详解J2EE支持JDBC事务、JTA事务和容器事务事务,这里说一下怎样实现JDBC事务。&
- 在线用户使用HttpSessionListener * 统计 每当一个session会话建立 在线用户人数+1每当一
- 问题用过storm或者jstorm的都知道,如果在bolt代码中发生了没被catch住的异常,所在worker进程会退出。本文就从源码角度分
- 定义建造者模式(Builder Pattern),又叫生成器模式,是一种对象构建模式 它可以将复杂对象的建造过程抽象出来,使这个抽象过程的不
- java实现接口签名为了保证数据传输的安全性,跟其他系统进行数据交互时,双方应该约定好密钥,把数据进行加密,接口签名,这样双方调用接口时,验
- 分页实现的基本过程是这样的:1. 设置自己的分页器的基本参数(可以从配置文件中读取)■每页显示的记录条数■每次最多显示多少页2. 编写设置分
- 近来总是接触到 IoC(Inversion of Control,控制反转)、DI(Dependency Injection,依赖注入)等编
- 一、二叉搜索树插入元素/** * user:ypc; * date:2021-05-18; * time: 15:09; */
- 这篇文章主要介绍了Spring Cache手动清理Redis缓存,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值
- 对于Hibernate刚刚学习了一周时间了,作为一名java初学者,也有点自己的感受想分享出来,如果这篇文章能有幸被大家看到,也仅供大家娱乐
- .ini 文件是Initialization File的缩写,即初始化文件,是windows的系统配置文件所采用的存储格式,统管window
- 最近接触到INI配置文件的读写,虽然很久以前微软就推荐使用注册表来代替INI配置文件,现在在Visual Stud
- 一、根据流向分为输入流和输出流:注意输入流和输出流是相对于程序而言的。输出:把程序(内存)中的内容输出到磁盘、光盘等存储设备中输入:读取外部
- 新手学习记录。写在springboot test 示例 示例代码地址看结尾。后面有带页面的示例。SpringBoot Test无
- 使用Myeclipse搭建maven项目准备工作安装maven官网下载安装(http://maven.apache.org/)配置环境变量配
- 本文实例讲述了Java面向对象程序设计:抽象类,接口用法。分享给大家供大家参考,具体如下:本文内容:抽象类接口抽象类与接口的异同
- 一. 多维数组1. 概念多维数组可以看成是数组的数组。 比如二维数组就是一个特殊的一维数组,它的每个元素都是一个一维数组。其他多维数组的概念
- 在Java的内存分配中,总共3种常量池:Java 常量池详解(二)class文件常量池 和 Java 常量池详解(三)class运行时常量池
- 背景SpringBoot 版本<parent> <groupId>org.springfr
- 本文主要介绍了java中LinkedList使用迭代器优化移除批量元素原理,分享给大家,具体如下:public interface Iter