使用线程池初衷
最近项目做代码优化,有一业务功能,大致描述为有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
不积跬步无以至千里
分享到:
相关推荐
Java多线程学习是编程领域中的重要一环,特别是在服务器端和网络编程中,多线程技术能够有效地利用系统资源,提高程序的并发性。FTP(File Transfer Protocol)上传则是通过网络将本地文件传输到远程服务器的过程。...
在多线程大师Doug Lea的贡献下,在JDK1.5中加入了许多对并发特性的支持,例如:线程池。.......................................JAVA线程、线程池资料----下载不扣分,回帖加1分,欢迎下载,童叟无欺JAVA线程、...
Java 多线程主题1- Java 多线程启动线程2- Java 多线程Volatile – 基本线程通信3- Java 多线程同步4- Java 多线程锁对象5- Java 多线程线程池6- Java 多线程倒计时闩锁7- Java 多线程生产者-消费者8- Java 多线程...
本资料“Java多线程学习-动力节点共22页.pdf.zip”提供了对Java多线程的深入学习,旨在帮助开发者掌握这一关键技术。 1. **线程基础**:Java中的线程是通过`Thread`类或者实现`Runnable`接口来创建的。通过继承`...
在“WHUT-java多线程实验-第三周-文件上传和下载.zip”这个实验中,我们将重点探讨如何在多线程环境中实现文件的上传和下载功能。这个实验基于IntelliJ IDEA开发环境,它是一个流行的Java集成开发环境,提供了丰富的...
总的来说,"Java多线程基础-01、数组概述"的学习将帮助你理解如何在Java中创建和管理线程,以及如何在多线程环境下安全地使用数组。通过深入学习这部分内容,你将具备编写高效并发程序的基础,为后续的多线程编程...
在Java编程中,多线程是并发编程的重要组成部分,它允许程序同时执行多个任务,从而提高了系统的效率和响应性。然而,在某些场景下,我们可能需要控制线程的执行顺序,确保它们按照特定的顺序交替运行,这在并发编程...
Java 多线程-Socket 编程 Java 多线程-Socket 编程是指在 Java 语言中使用多线程技术来实现网络编程,特别是使用 Socket 编程来实现客户端和服务器端的通信。在 Java 中,多线程可以使用 Thread 类和 Runnable 接口...
在Java多线程编程中,有时我们需要确保所有子线程执行完毕后再进行后续操作,例如在并发测试、数据聚合或资源清理等场景。本篇文章将详细介绍五种在Java中等待所有子线程执行完的方法。 ### 方法一:使用`sleep`...
线程的状态管理是多线程编程中非常重要的部分。Java线程有六种状态:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED。NEW表示线程刚创建还未启动,RUNNABLE表示线程在执行或等待CPU资源,BLOCKED表示...
Java线程:新特征-线程池 Java线程:新特征-有返回值的线程 Java线程:新特征-锁(上) Java线程:新特征-锁(下) Java线程:新特征-信号量 Java线程:新特征-阻塞队列 Java线程:新特征-阻塞栈 Java线程:新特征-...
在"WHUT-java多线程实验-第二周-异常处理"这个实验中,我们将学习如何在多线程环境下进行异常捕获和处理。实验基于IntelliJ IDEA这个强大的Java集成开发环境进行,IDEA提供了友好的界面和丰富的工具,方便我们进行...
Java并发编程实践中的线程池是一个关键的概念,它在多线程编程中扮演着至关重要的角色,有效地管理和调度线程资源,以提高系统的性能和效率。线程池通过复用已存在的线程来减少线程的创建和销毁开销,避免了频繁的上...
Java多线程编程,生命游戏,用线程池.zipJava多线程编程,生命游戏,用线程池.zip Java多线程编程,生命游戏,用线程池.zipJava多线程编程,生命游戏,用线程池.zip Java多线程编程,生命游戏,用线程池.zipJava多...
综上所述,"java多线程查询数据库"是一个涉及多线程技术、线程池管理、并发控制、分页查询等多个方面的复杂问题。通过理解和掌握这些知识点,我们可以有效地提高数据库操作的效率和系统的响应速度。
Java多线程实现数据切割批量执行,实现限流操作。 java线程池Executors实现数据批量操作。 批量异步Executors处理数据,实现限流操作,QPS限流。 线程池调用第三方接口限流实现逻辑。 案例适合: 1.批量处理大数据。...
### Java多线程分页查询知识点详解 #### 一、背景与需求分析 在实际的软件开发过程中,尤其是在处理大量数据时,如何高效地进行数据查询成为了一个关键问题。例如,在一个用户众多的社交平台上,当用户需要查看...
在本示例中,“java多线程例子-生产者消费者”旨在展示如何利用多线程来实现生产者和消费者模式。这种模式是并发编程中的经典设计模式,用于协调生产数据和消费数据的两个不同线程。 生产者消费者模式的基本概念是...
除了`ThreadPoolExecutor`,Java还提供了`Executors`工具类,它提供了一些预设的线程池配置,如`newFixedThreadPool`(固定大小线程池)、`newSingleThreadExecutor`(单线程线程池)等,方便开发者快速创建线程池。...