您的位置:首页 > 其它

判断线程池中的线程是否全部执行完毕

2017-03-17 14:26 686 查看



StoneFeng

做一个有梦想的程序员,万一哪天梦想实现了呢?

博客园
首页
新随笔
联系
订阅

判断线程池中的线程是否全部执行完毕

在使用多线程的时候有时候我们会使用 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方法等待计数器达到零,即表示需要等待的事情都已经发生。可以使用闭锁来这样设计程序达到目的:



1 public class CountDownLatchApproach {
2     public static void main(String[] args) throws IOException, InterruptedException {
3         final int nThreads = 10;
4         final CountDownLatch endGate = new CountDownLatch(nThreads);
 5         final File stream = new File("c:\\temp\\stonefeng\\stream.txt");
6         final OutputStream os = new FileOutputStream(stream);
7         final OutputStreamWriter writer = new OutputStreamWriter(os);
8         ExecutorService exec = Executors.newCachedThreadPool();
9         for (int i = 0; i < nThreads; i++) {
10             final int num = i;
11             Runnable task = new Runnable() {
12                 @Override
13                 public void run() {
14                     try {
15                         writer.write(String.valueOf(num)+"\n");
16                     } catch (IOException e) {
17                         e.printStackTrace();
18                     } finally {
19                         endGate.countDown();
20                     }
21                 }
22             };
23             exec.submit(task);
24         }
25         endGate.await();
26         writer.write("---END---\n");
27         writer.close();
28     }
29 }




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

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



1 public class MySemaphore {
2
3     public static void main(String[] args) throws IOException, InterruptedException {
4         final File stream = new File("c:\\temp\\stonefeng\\stream.txt");
5         final OutputStream os = new FileOutputStream(stream);
6         final OutputStreamWriter writer = new OutputStreamWriter(os);
7         final Semaphore semaphore = new Semaphore(10);
8         ExecutorService exec = Executors.newCachedThreadPool();
9
10         final long start = System.currentTimeMillis();
11         for (int i = 0; i < 10000000; i++) {
12             final int num = i;
13             Runnable task = new Runnable() {
14                 @Override
15                 public void run() {
16                     try {
17                         semaphore.acquire();
18                         writer.write(String.valueOf(num)+"\n");
19                         semaphore.release();
20                     } catch (IOException e) {
21                         e.printStackTrace();
22                     } catch (InterruptedException e) {
23                         e.printStackTrace();
24                     }
25                 }
26             };
27             exec.submit(task);
28         }
29         exec.shutdown();
30         exec.awaitTermination(1, TimeUnit.HOURS);
31         writer.write("---END---\n");
32         writer.close();
33         System.out.println("ËùÓеÄ×ÓÏ̶߳¼½áÊøÁË£¡");
34         final long end = System.currentTimeMillis();
35         System.out.println((end-start)/1000);
36     }
37 }




 

分类:
Core Java

好文要顶
关注我 收藏该文








StoneFeng
关注 - 13
粉丝 - 9

+加关注

0
0

«
上一篇:一个简单的死锁
»
下一篇:Java多线程的信号量

posted @ 2016-10-16 19:44
StoneFeng 阅读(1857) 评论(0)

编辑
收藏

刷新评论刷新页面返回顶部

注册用户登录后才能发表评论,请
登录 或 注册,访问网站首页。

【推荐】50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
【免费】自开发零实施的H3 BPM免费下载
【推荐】Google+GitHub联手打造前端工程师课程
【云上】在金山大米云,让云计算更简单
【推荐】阿里云香港云服务器65折,免备案





最新IT新闻:

· Airbnb去年清掉923处不合规定的房源

· 谷歌开源“Guetzli”JPEG图像编码器:提升压缩比、网页加载更顺滑

· 万宝龙推出首款Android Wear智能手表

· Apple Music大使计划 推特推广可免费获得3个月会员

· Windows 10 Build 15060发布:本周的第三个版本更新

»
更多新闻...





最新知识库文章:
·
为什么我要写自己的框架?

· 垃圾回收原来是这么回事

· 「代码家」的学习过程和学习经验分享

· 写给未来的程序媛

· 高质量的工程代码为什么难写

» 更多知识库文章...

公告

昵称:StoneFeng

园龄:4年6个月

粉丝:9

关注:13
+加关注

<2017年3月>
2627281234
567891011
12131415161718
19202122232425
2627282930311
2345678

搜索

 
 

常用链接

我的随笔
我的评论
我的参与
最新评论
我的标签

随笔分类

Core Java(6)

Hibernate(3)

Spring(3)

Struts(2)

设计模式(12)

随笔档案

2017年1月 (1)

2016年12月 (4)

2016年11月 (4)

2016年10月 (3)

2016年9月 (2)

2016年8月 (19)

2016年7月 (17)

2012年9月 (2)

2012年8月 (5)

最新评论

1. Re:设计模式学习笔记之九:模板方法模式
HttpServlet中的doGet,doPost,doXXX方法也是模板方法模式的一种具体样例。
--StoneFeng
2. Re:设计模式学习笔记之九:模板方法模式
java.util.Arrays的sort方法就是使用的模板方法模式,如果你要对一个对象数组排序,你首先需要使该类实现Comparable接口并实现其compareTo方法,然后调用Arrays.so......
--StoneFeng
3. Re:如何自定义JSR-303标准的validator
@小董的记事本是的,谢谢提醒。...
--石头Feng
4. Re:使用抽象工厂模式来解决遗留代码中的紧耦合和难维护的问题
@joe.fan我们公司用的是法国达索Enovia PLM系统...
--石头Feng
5. Re:如何自定义JSR-303标准的validator
哥们if (isNumeric(id) && (length == 15 || length == 18)) {身份证号码并不是全数字,还有X结尾的。...
--小董的记事本

阅读排行榜

1. Troubleshooting - eclipse在debug视图中不显示变量值的解决方案(2296)
2. 判断线程池中的线程是否全部执行完毕(1857)
3. 如何用命令行更新Ubuntu ?(507)
4. 如何关闭tomcat的localhost_access_log?(492)
5. 把嵌入在eclipse中的tomcat日志分离出来(491)

评论排行榜

1. 设计模式学习笔记之八:外观模式(4)
2. Troubleshooting - 当xml文件中存在"&"符号的时(2)
3. 如何自定义JSR-303标准的validator(2)
4. 设计模式学习笔记之九:模板方法模式(2)
5. 使用抽象工厂模式来解决遗留代码中的紧耦合和难维护的问题(2)

推荐排行榜

1. 设计模式学习笔记之九:模板方法模式(2)
2. 设计模式学习笔记之八:外观模式(2)
3. 高可用集群架构的演进(1)
4. Hibernate中session.get()和session.load()的区别(1)

Copyright ©2017 StoneFeng
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: