使用线程池初衷
最近项目做代码优化,有一业务功能,大致描述为有20几台分机往总机发送文件,总机在收到文件之后,会往分机反馈数据处理情况。
这时候想到使用调度来查询总机收到的消息,处理之后分别发送至各分机,为避免排队处理,决定使用多线程,并使用线程池来管理。
创建线程池
查找资料之后,采用JDK1.5的java.util.concurrent包创建线程池,本例使用可重用固定线程数的线程池,代码如下:
private static int maxThreads = 20; //最大线程数
private static ExecutorService e = Executors.newFixedThreadPool(maxThreads); //创建一个有固定数量线程的线程池
获取任务执行结果
然后,我使用了FutureTask类来获取任务执行结果,并可以设置任务超时时间,代码如下:
FutureTask<Boolean> ft = new FutureTask<Boolean>(thread,true);
e.execute(ft);
Boolean fTaskResult = ft.get(); //不设置等待时间,等待计算完成,获取结果
//Boolean fTaskResult = ft.get(fTimeout, TimeUnit.SECONDS); //设置等待时间,时间到了之后,获取任务执行结果,如果超时,则会抛出TimeoutException异常
如果任务执行超时,我们可以调用FutureTask类的cancel(boolean mayInterruptIfRunning)方法来请求中断任务;
参数mayInterruptIfRunning - 如果应该中断执行此任务的线程,则为 true;否则允许正在运行的任务运行完成,代码如下:
catch (TimeoutException e) {
System.out.println("主线程等待计算结果超时,因此中断任务线程");
ft.cancel(true);
}
但是,这样存在一个问题,就是在调用FutureTask对象的get()方法时,会阻塞线程,直到任务执行完成,会阻止其他线程的执行,网上搜索无果,就用线程池又打开一个线程执行FutureTask对象的get()方法,代码如下:
/**
* 执行任务
* @param t 线程对象
*/
public static void beginTask(Thread t){
e.execute(t);
}
/**
* 不设置超时时间的任务调用
* @param key 线程标识
* @param t 线程对象
*/
public static void beginTask(String key,Thread thread){
final String fKey = key;
final FutureTask<Boolean> ft = new FutureTask<Boolean>(thread,true);
runningTaskMap.put(key, ft); //存储任务标识
e.execute(ft);
beginTask(new Thread(){
@Override
public void run() {
// TODO Auto-generated method stub
try {
Boolean fTaskResult = ft.get();
if(fTaskResult){
System.out.println("key为:"+fKey+"的线程执行完成");
}
} catch (InterruptedException e) {
System.out.println("主线程在等待计算结果时被中断");
} catch (ExecutionException e) {
System.out.println("主线程等待计算结果,但计算抛出异常");
}finally{
runningTaskMap.remove(fKey); //移除线程标识
}
}
});
}
任务标记
另外,为了能够获取正在执行的任务,我们对每个任务做了标记,存放在map集合中,代码如下:
//创建一个带有标识的任务集合
private static Map<String, FutureTask<Boolean>> runningTaskMap = Collections.synchronizedMap(new HashMap<String, FutureTask<Boolean>>());
当每次调用线程池,就会往map集合中存放记录,调用完之后,再移除掉。
我们也可以通过标识来中断正在执行的任务,代码如下:
/**
* 根据传入的任务标识,来中断对应任务
* @param key 任务标识
*/
public static void intteruptTask(String key){
FutureTask<Boolean> ft = runningTaskMap.get(key);
ft.cancel(true);
if(ft.isDone()){
runningTaskMap.remove(key);
}
}
最后附上完整代码:
package task.concurrent.threadPoor;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class FixedThreadPool {
private static int maxThreads = 20; //最大线程数
private static ExecutorService e = Executors.newFixedThreadPool(maxThreads); //创建一个有固定数量线程的线程池
//创建一个带有标识的任务集合
private static Map<String, FutureTask<Boolean>> runningTaskMap = Collections.synchronizedMap(new HashMap<String, FutureTask<Boolean>>());
/**
* 执行任务
* @param t 线程对象
*/
public static void beginTask(Thread t){
e.execute(t);
}
/**
* 不设置超时时间的任务调用
* @param key 线程标识
* @param t 线程对象
*/
public static void beginTask(String key,Thread thread){
final String fKey = key;
final FutureTask<Boolean> ft = new FutureTask<Boolean>(thread,true);
runningTaskMap.put(key, ft); //存储任务标识
e.execute(ft);
beginTask(new Thread(){
@Override
public void run() {
// TODO Auto-generated method stub
try {
Boolean fTaskResult = ft.get();
if(fTaskResult){
System.out.println("key为:"+fKey+"的线程执行完成");
}
} catch (InterruptedException e) {
System.out.println("主线程在等待计算结果时被中断");
} catch (ExecutionException e) {
System.out.println("主线程等待计算结果,但计算抛出异常");
}finally{
runningTaskMap.remove(fKey); //移除线程标识
}
}
});
}
/**
* 设置有超时时间的任务调用
* @param key 线程标识
* @param thread 线程对象
* @param timeout 秒
*/
public static void beginTask(String key, Thread thread, int timeout) {
final String fKey = key;
final int fTimeout = timeout;
final FutureTask<Boolean> ft = new FutureTask<Boolean>(thread,true);
runningTaskMap.put(key, ft); //存储任务标识
e.execute(ft);
beginTask(new Thread(){
@Override
public void run() {
// TODO Auto-generated method stub
try {
Boolean fTaskResult = ft.get(fTimeout, TimeUnit.SECONDS);
if(fTaskResult){
System.out.println("key为:"+fKey+"的线程执行完成");
}
} catch (InterruptedException e) {
System.out.println("主线程在等待计算结果时被中断");
} catch (ExecutionException e) {
System.out.println("主线程等待计算结果,但计算抛出异常");
} catch (TimeoutException e) {
System.out.println("主线程等待计算结果超时,因此中断任务线程");
ft.cancel(true);
}finally{
runningTaskMap.remove(fKey); //移除线程标识
}
}
});
}
/**
* 根据传入的任务标识,来中断对应任务
* @param key 任务标识
*/
public static void intteruptTask(String key){
FutureTask<Boolean> ft = runningTaskMap.get(key);
ft.cancel(true);
if(ft.isDone()){
runningTaskMap.remove(key);
}
}
/**
* 关闭线程池
*/
public static void shutDownPool(){
e.shutdown();
}
}
总结:调用及测试代码就不贴出来了,由于是初写线程池代码,有很多不足之处,望网友能够指出,相互学习进步。
参考资料:
http://blog.csdn.net/hemingwang0902/article/details/4557304
http://westyi.iteye.com/blog/714935
不积跬步无以至千里
分享到:
相关推荐
在多线程大师Doug Lea的贡献下,在JDK1.5中加入了许多对并发特性的支持,例如:线程池。.......................................JAVA线程、线程池资料----下载不扣分,回帖加1分,欢迎下载,童叟无欺JAVA线程、...
java多线程,对多线程,线程池进行封装,方便使用
Java 线程系列博文总结word化,编目如下,欢迎互相学习交流: Java线程:概念与原理 Java线程:创建与启动 Java线程:线程栈模型与线程的变量 Java线程:线程状态的转换 Java线程:线程的同步与锁 Java线程:...
详细的讲述了多线程的各种用法 Java线程:概念与原理 Java线程:创建与启动 Java线程:线程栈模型与线程的变量 Java线程:线程状态的转换 Java线程:线程的同步与锁 Java线程:线程的交互 Java线程:线程的调度-休眠...
Java多线程编程,生命游戏,用线程池.zipJava多线程编程,生命游戏,用线程池.zip Java多线程编程,生命游戏,用线程池.zipJava多线程编程,生命游戏,用线程池.zip Java多线程编程,生命游戏,用线程池.zipJava多...
Java多线程实现数据切割批量执行,实现限流操作。 java线程池Executors实现数据批量操作。 批量异步Executors处理数据,实现限流操作,QPS限流。 线程池调用第三方接口限流实现逻辑。 案例适合: 1.批量处理大数据。...
java多线程并发查询数据库,使用线程池控制分页,并发查询。
Java 多线程与并发(17_26)-JUC线程池_ FutureTask详解
Java多线程是一块重要的内容,李兴华讲解的Java是一个很好的资源
JAVA使用线程池查询大批量数据
Java多线程--JDK5.0新增线程创建方式
java多线程实现大批量数据切分成指定份数的数据,然后多线程处理入库或者导出,线程的个数和每份数据的数量都可以控制
用于数据量大的情况下预先查询出数据,加快对后面页面数据的查询速度
本压缩包,总共包含两个文档,JAVA多线程编程详解-详细操作例子和 Java多线 程编程总结 例如,runnable、thread、stop()、 suspend、yield、setPriority()、getPriority()、synchronized、wait()、join、线程池同步...
java多线程加队列上传文件_后台处理
目标:Java中多线程技术是一个难点,但是也是一个核心技术。因为Java本身就是一个多线程语言。本人目前在给46班讲授Swing的网络编程--使用Swing来模拟真实的QQ实时聊天软件。因为涉及到Socket编程,所以一定会使用多...
Java线程池及观察者模式解决多线程意外死亡重启问题,附件含两个要运行代码!