最近在项目中需要使用多线程的并发来处理数据,刚开始希望使用static关键字来控制总的请求数,通过加减计数来进行数据请求的调度,本来并发量就不是很高,可是在实际的实验环境中,因为不能很好的控制请求的先后顺序,达到FIFO的要求,所以准备改善优化一下。对于线程池的使用不是很熟悉,通过网上的一些实例,结合自己的实际需求,对现成的一个实例,进行了优化,希望给各位有新的启发。
根据需求,主要做两方面的改正:
1.要对子线程的结果进行判断,这要求ExecutorService的执行结果必须有返回值
2.要捕获子线程的自定义异常。
首先第1点,获取任务的执行的返回值。
ExecutorService能够执行的任务分两类:一类是实现了Runnable接口的类,一类是实现了Callable接口的类。两者都可以被ExecutorService执行,但是Runnable任务没有返回值,而Callable任务有返回值。并且Callable的call()方法只能通过ExecutorService的(
import java.util.Random;
import java.util.concurrent.Callable;
public class TaskWithResult implements Callable
private int id;
private static final String RESULT_NG_39 = "39";
public TaskWithResult(int id) {
this.id = id;
}
/**
* 任务的具体过程,一旦任务传给ExecutorService的submit方法,则该方法自动在一个线程上执行。
*
* @return
* @throws Exception
*/
public String call() throws TaskException {
System.out.println("call()方法被自动调用,干活!!! "
+ Thread.currentThread().getName());
if (new Random().nextBoolean())
// 此处为自定义的exception, 包含返回的error code,在实际的开发中,不同的错误会对应不同的code
throw new TaskException("Meet error in task."
+ Thread.currentThread().getName(), RESULT_NG_39);
// 一个模拟耗时的操作
for (int i = 999999999; i > 0; i--)
;
// return "OK";
return "call()方法被自动调用,任务的结果是:" + id + " "
+ Thread.currentThread().getName();
}
}
第二.要捕获子线程的自定义异常。
这个是很关键的一环,项目开发中会有各种类型的异常,各种不同的message,errorcode,能够分门别类的正确区分抛出,对以后维护调试起到事半功倍的作用。
自定义的异常类:
package threatPool;
public class TaskException extends Exception {
/**
*
*/
private static final long serialVersionUID = 11583612349862927L;
public String getErrorCode() {
return errorCode;
}
public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
}
private String errorCode;
// 主要是希望通过errorCode的不同,区分不同业务段的不同error
public TaskException(String message, String errorCode) {
super(message);
setErrorCode(errorCode);
}
}
最后,main函数调用:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ExecutorServiceTest {
private static final String RESULT_NG_39 = "39";
public static void main(String[] args) throws TaskException {
ExecutorService executorService = Executors.newCachedThreadPool();
List
// 创建10个任务并执行
for (int i = 0; i < 10; i++) {
// 使用ExecutorService执行Callable类型的任务,并将结果保存在future变量中
TaskWithResult tr = new TaskWithResult(i);
// 使用的submit,非excute方法
Future
// 将任务执行结果存储到List中
resultList.add(future);
}
executorService.shutdown();
// 遍历任务的结果
for (Future
try {
// 打印各个线程(任务)执行的结果
System.out.println(fs.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
// 获得子线程中抛出的异常code,注意此时使用的e.getCause(),对象的转型使用,我们在
// 实际项目中不是简简单单的获得这个exception打印出来,而是通过这个exception获得更多的信息
String errorCode = ((TaskException) e.getCause())
.getErrorCode();
if(RESULT_NG_39.equals(errorCode)){
// log.info("XXXXXXXXXXXXXXXX");
}
// e.printStackTrace();
return;
}
}
}
}
执行结果:
call()方法被自动调用,干活!!! pool-1-thread-1
call()方法被自动调用,干活!!! pool-1-thread-2
call()方法被自动调用,干活!!! pool-1-thread-3
call()方法被自动调用,干活!!! pool-1-thread-5
call()方法被自动调用,干活!!! pool-1-thread-4
call()方法被自动调用,干活!!! pool-1-thread-6
call()方法被自动调用,干活!!! pool-1-thread-7
call()方法被自动调用,干活!!! pool-1-thread-8
call()方法被自动调用,干活!!! pool-1-thread-10
call()方法被自动调用,干活!!! pool-1-thread-9
call()方法被自动调用,任务的结果是:0 pool-1-thread-1
call()方法被自动调用,任务的结果是:1 pool-1-thread-2
the error code is 39 !
the error code is 39 !
call()方法被自动调用,任务的结果是:4 pool-1-thread-5
call()方法被自动调用,任务的结果是:5 pool-1-thread-6
call()方法被自动调用,任务的结果是:6 pool-1-thread-7
the error code is 39 !
call()方法被自动调用,任务的结果是:8 pool-1-thread-9
call()方法被自动调用,任务的结果是:9 pool-1-thread-10
感谢各位前人的demo,也希望给大家一些启示。