通过java.util.concurrent写多线程程序
package com.giantray; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class TestConcurrent { public static ExecutorService exec = Executors.newCachedThreadPool(); public void startMutilThread()
{
int taskNum = 2;
final CountDownLatch cd = new CountDownLatch(taskNum ); //任务1
exec.submit(new Runnable(){ @Override
public void run()
{
System. out.println("1 start" );
try {
Thread. sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cd.countDown();
System. out.println("1 end" );
} }); //任务2
exec.submit(new Runnable(){ @Override
public void run()
{
System. out.println("2 start" );
cd.countDown();
System. out.println("2 end" );
} }); System. out.println("submit end" );
try
{
cd.await();
}
catch (InterruptedException e)
{ }
System. out.print("end" );
}
public static void main(String[] args) {
TestConcurrent testThread = new TestConcurrent();
testThread.startMutilThread();
}
}
1 start
submit end
2 start
2 end
1 end
end
一、使用流程
2、final CountDownLatch cd = new CountDownLatch(taskNum ); 定义计数器,指定要并发执行的任务数
3、 exec .submit( new Runnable(){};定义任务的执行逻辑
4、cd.countDown();任务结束了,要让计算器减1
5、cd.await();表示等待计数器小于等于0时,再继续往下走其他逻辑
二、线程池的管理
除了示例中的newCachedThreadPool(),也有其他各种类型的线程池:
1、newFixedThreadPool(固定大小线程池)
线程数是固定的,例如线程数设为1,则需要等待任务1结束后,才执行任务2;如设为2,则两个任务能同时执行
2、newCachedThreadPool(无限制大小的线程池)
线程数无固定大小,当前无可用线程,就回创建新线程。如果任务1没结束,那么启动任务2时,就会新建线程,这时线程池大小为2;但假如启动任务2时,任务1已结束,则不会新建线程,会沿用任务1使用的线程
3、newSingleThreadExecutor(单线程)
使用单线程池时,就没办法同时执行多个任务,因此,本例中的任务1执行完后,才会执行任务2
4、newScheduledThreadPool(定时任务线程池)
支持定时任务的线程池,与Timer,Quartz一样,常见于一些定时任务调度程序·
三、计数器CountDownLatch
1、示例讲解
在示例中,我们通过多线程执行了两个任务。之后我们需要知道,两个任务是否都执行结束?都执行结束了,我们才能继续执行接下来的其他逻辑。为了这个目的,需要引入CountDownLatch这个计数器。先声明一个计算量为TaskNum(2)的计数器,接着,每个任务执行结束时,要执行countDown()方法,而最后的await()方法表示,如果CountDownLatch不为零,那么就在这里等待,下面的逻辑会被阻塞住,不会继续执行,等待两个任务都执行结束了--执行两次countDown()方法,计数器等于0,这时候程序才会继续往下执行System. out.print("end")这行代码
2、它的兄弟CyclicBarrier
还有一个类似CountDownLatch的计数器,名为CyclicBarrier。这两者的区别:CountDownLatch被减至0后,是不能重置的。而CyclicBarrier被减至0后,会自动恢复至初始值,因此它是一个循环的计数器,举一个例子,运动员跑步,这是一个任务,而这个任务,又分为运动员准备,以及开跑两个子任务,所有的运动员,必须等待其他运动员都”准备“好后,才能起跑。为了实现这个逻辑,及可以用到CyclicBarrier,CyclicBarrier的计数初始值为运动员数量,运动员准备完毕时,让计数器减1,这时候它不会进行”开跑“,等到计数器减为0时,所有运动员才同时“起跑”,并且会重新恢复至初始值,等到所有运动员都跑完时,计数器才又恢复为0,这时候,才能再继续执行其他任务。而如果使用CyclicBarrier,在线程执行过程中,是不能等待其他线程的,不能等其他线程都“准备”好了,所有线程再一起“开跑”
四、并发执行
多运行几次示例程序,会发现,有时候,"2 start"会早于"1 start"输出,因此,不一定是先submit的任务,就先“开始执行”。这也告诉我们,不能想当然地以为,任务1先submit,就可以在任务1里做一些全局初始化的工作,然后在任务2里可以去拿任务1初始化的变量。
五、线程池的生命周期管理
1、三种基本状态
线程池的声明周期有三个状态,运行,关闭,终止。初始化线程时,处于运行状态,执行shutdown()方法后,处于关闭状态,但这时候线程任务会继续执行,当所有任务都结束后,才会变成终止状态。
2、shutdown()与shutdownNow()的区别
这两个方法都用于关闭线程池
shutdown() 关闭线程池,但之前提交的任务,会继续执行;如果新提交任务,会抛异常
shutdownNow() 马上关闭线程池,之前提交的任务,如果还未执行完,会被终止,且抛出异常
3、shutdown()的作用
- 释放线程池资源(其实不关闭线程池,会资源会有多大的消耗,笔者也不清楚)
- 可以让程序有序退出。这是什么意思呢?讲一个例子,你就明白了。假如你的程序正在并发执行任务,而且还一直会提交新的任务。这时候,该如何设计程序的“退出”功能呢?首先,为了任务的原子性,希望能执行完已提交的任务,并且阻止新的任务提交。这时候,就得用到了shutdown()了。退出功能的代码可以是这样:
System.out.println("准备退出程序");
service.shutdown();
while (true) {
try {
System.out.println("等待“已提交任务”执行结束");
//awaitTerminationm,先等待5秒,再检查任务是否结束
if (service.awaitTermination(5, TimeUnit.SECONDS)) {
break;
}
} catch (InterruptedException e) {
}
}
System.out.println("”已提交任务“执行完,程序可以安全退出");
六、获取线程任务的执行结果
如果想知道任务的执行结果,就得使用Future和Callable。Future可以拿到结果,而Callable能返回值,用于产生结果
对示例代码做下修改,其中,task1.get()将拿到call()方法的return值,也就是示例中的"false"
int taskNum = 1;
final CountDownLatch cd = new CountDownLatch(taskNum); Future<Boolean> task1 = exec.submit(new Callable<Boolean>(){ @Override
public Boolean call() throws Exception {
System.out.println("1 start"); cd.countDown(); System.out.println("1 end");
return false;
} }); try {
cd.await();
Boolean result = task1.get();
System.out.println("result : " + result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.print("end");
通过java.util.concurrent写多线程程序的更多相关文章
- java.util.concurrent包API学习笔记
newFixedThreadPool 创建一个固定大小的线程池. shutdown():用于关闭启动线程,如果不调用该语句,jvm不会关闭. awaitTermination():用于等待子线程结束, ...
- Java多线程:CAS与java.util.concurrent.atomic
锁的几种概念 悲观锁 总是假设最坏的情况,每次获取数据都认为别人会修改,所以拿数据时会上锁,一直到释放锁不允许其他线程修改数据.Java中如synchronized和reentrantLock就是这种 ...
- java 多线程 集合的包装方法Collections.synchronizedXXXXX;线程安全的集合类:Java.util.concurrent.ConcurrentXXX;java.util.concurrent.CopyOnWriteXXXX
问题:ArrayList 等线程不安全 当多线程并发修改一个集合数据时,可能同一个下标位置被覆盖. 示例代码: 一个List,我们创建10个线程,每个线程往这个List中添加1000条数据,结果往往 ...
- [转载] java多线程学习-java.util.concurrent详解(一) Latch/Barrier
转载自http://janeky.iteye.com/blog/769965 Java1.5提供了一个非常高效实用的多线程包:java.util.concurrent, 提供了大量高级工具,可 ...
- java多线程学习--java.util.concurrent (转载)
题记:util和concurrent 包是后续重点先看的和学习的模块 原文地址:http://www.cnblogs.com/sunhan/p/3817806.html CountDownLatch, ...
- java多线程学习--java.util.concurrent
CountDownLatch,api 文档:http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.h ...
- Java:多线程,java.util.concurrent.atomic包之AtomicInteger/AtomicLong用法
1. 背景 java.util.concurrent.atomic这个包是非常实用,解决了我们以前自己写一个同步方法来实现类似于自增长字段的问题. 在Java语言中,增量操作符(++)不是原子的,也就 ...
- 多线程包:java.util.concurrent,
Java1.5提供了一个非常高效实用的多线程包:java.util.concurrent,
- java.util.concurrent 多线程框架
http://daoger.iteye.com/blog/142485 JDK5中的一个亮点就是将Doug Lea的并发库引入到Java标准库中.Doug Lea确实是一个牛人,能教书,能出书,能编码 ...
随机推荐
- 和学生探讨吉林大学python问题
学生们真的很强大,我知道玩微信,nodejs.... 我们去学校了解.当时互联网开始64K....
- 谁的用户在世界上是  明基决心保时捷设计标准
谈到保时捷.相信非常多人都非常了解,世界名车啊,仅仅有高富帅才玩儿得起.只是,假设由保时捷的设计师来设计一款显示器,水准一流.质地厚道,且价格亲民,你怎么看? 如近期京东上热销的明基G ...
- GUI & Event例子
Student No.: _______________ Name: ________________________________________1TK2934 Object-Oriented P ...
- C语言中main函数的參数具体解释
main函数的定义形式 main函数能够不带參数,也能够带參数,这个參数能够觉得是 main函数的形式參数.C语言规定main函数的參数仅仅能有两个,习惯上这两个參数写为argc和ar ...
- Eclipse项目崩溃,使用MyEclipse解决
在今天的项目,Eclipse 在Rwenjian崩溃,导致项目全红 叉 并且不提示任务的错误信息. 无奈之下想起MyEclipse老板. 复制项目MyEclipse文件夹下. 之后,在MyEclip ...
- Python多线程的threading Event
Python threading模块提供Event对象用于线程间通信.它提供了一组.拆除.等待用于线程间通信的其他方法. event它是沟通中最简单的一个过程之中,一个线程产生一个信号,号.Pytho ...
- SQL 编码标准
1. 你必须从别名表,易于使用的表,该表列 实例 select owner,object_id,name from a,b where a.id=b.id; 假设是不正确的别名表.我知道你是怎么访问表 ...
- 最近做RTSP流媒体的实时广播节目
//h264视频流打包代码 // NALDecoder.cpp : Defines the entry point for the console application. #include < ...
- Java获取的一天、本星期、这个月、本季度、一年等 开始和结束时间
1.代码 package com.zhaochao.utils; import java.text.SimpleDateFormat; import java.util.Calendar; impor ...
- hdu4288 Coder(段树+分离)
主题链接: huangjing 题意: 题目中给了三个操作 1:add x 就是把x插进去 2:delete x 就是把x删除 3:sum 就是求下标%5=3的元素的和. 另一个条件是插入和删除最后 ...