线程池扩展——回调:
public class EXTThreadPool {
private static final int THREADPOOLCORESIZE= 5 ;
private static final int THREADPOOLMAXSIZE= 5 ;
public static void main ( String[ ] args) {
ExecutorService exec= new ThreadPoolExecutor ( THREADPOOLCORESIZE, THREADPOOLMAXSIZE, 0 L, TimeUnit. SECONDS, new LinkedBlockingDeque < Runnable> ( ) ) {
@Override
protected void beforeExecute ( Thread t, Runnable r) {
System. out. println ( ( ( ExtThread) r) . getThreadName ( ) + "准备执行任务" ) ;
}
@Override
protected void afterExecute ( Runnable r, Throwable t) {
System. out. println ( ( ( ExtThread) r) . getThreadName ( ) + "完成任务" ) ;
}
@Override
protected void terminated ( ) {
System. out. println ( "线程池关闭" ) ;
}
} ;
for ( int i = 0 ; i < 5 ; i++ ) {
ExtThread td= new ExtThread ( ) ;
td. setThreadName ( "Thread-" + i) ;
exec. execute ( td) ;
}
exec. shutdown ( ) ;
}
}
class ExtThread implements Runnable {
private String ThreadName;
public String getThreadName ( ) {
return ThreadName;
}
public void setThreadName ( String threadName) {
ThreadName = threadName;
}
@Override
public void run ( ) {
System. out. println ( ThreadName+ "正在执行任务" ) ;
}
}
执行结果
Thread- 1 准备执行任务
Thread- 3 准备执行任务
Thread- 2 准备执行任务
Thread- 0 准备执行任务
Thread- 0 正在执行任务
Thread- 2 正在执行任务
Thread- 3 正在执行任务
Thread- 3 完成任务
Thread- 1 正在执行任务
Thread- 1 完成任务
Thread- 4 准备执行任务
Thread- 2 完成任务
Thread- 0 完成任务
Thread- 4 正在执行任务
Thread- 4 完成任务
线程池关闭
拒绝策略
线程池四种拒绝策略:
AbortPolicy(线程池默认使用的拒绝策略)
该策略在当任务访问超出最大值时,则会抛出异常并打印当前任务信息。 public static class AbortPolicy implements RejectedExecutionHandler {
public AbortPolicy ( ) { }
public void rejectedExecution ( Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException ( "Task " + r. toString ( ) +
" rejected from " +
e. toString ( ) ) ;
}
}
CallerRunsPolicy
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public CallerRunsPolicy ( ) { }
public void rejectedExecution ( Runnable r, ThreadPoolExecutor e) {
if ( ! e. isShutdown ( ) ) {
r. run ( ) ;
}
}
}
DiscardPolicy
public static class DiscardPolicy implements RejectedExecutionHandler {
public DiscardPolicy ( ) { }
public void rejectedExecution ( Runnable r, ThreadPoolExecutor e) {
}
}
DiscardOldestPolicy
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
public DiscardOldestPolicy ( ) { }
public void rejectedExecution ( Runnable r, ThreadPoolExecutor e) {
if ( ! e. isShutdown ( ) ) {
e. getQueue ( ) . poll ( ) ;
e. execute ( r) ;
}
}
}
自定义拒绝策略
如果以上的拒绝策略都不满足的话可以通过自定义拒绝策略。首先需要实现RejectedExecutionHandler接口,之后rejectedExecution方法中添加对应的业务实现即可。
触发拒绝策略的条件:public void execute ( Runnable command) {
if ( command == null)
throw new NullPointerException ( ) ;
int c = ctl. get ( ) ;
if ( workerCountOf ( c) < corePoolSize) {
if ( addWorker ( command, true ) )
return ;
c = ctl. get ( ) ;
}
if ( isRunning ( c) && workQueue. offer ( command) ) {
int recheck = ctl. get ( ) ;
if ( ! isRunning ( recheck) && remove ( command) )
reject ( command) ;
else if ( workerCountOf ( recheck) == 0 )
addWorker ( null, false ) ;
}
else if ( ! addWorker ( command, false ) )
reject ( command) ;
}
ForkJoinPool(可任务拆分的线程池)
ForkJoinPool通过一个任务分成若干个小任务,最后在将小任务的结果进行汇总,得到大任务的结果。通过fork方法分配子任务,在通过join方法获取到任务的结果。 ForkJoinPool的应用:
代码说明:public class ForJoinTest {
private static List< Integer> list= new ArrayList < Integer> ( ) ;
public static void main ( String[ ] args) throws Exception {
for ( int i= 0 ; i< 1000 ; i++ ) {
list. add ( new Random ( ) . nextInt ( 10 ) ) ;
}
ForkJoinPool exec= new ForkJoinPool ( 10 ) ;
SumThread sumThread= new SumThread ( list) ;
ForkJoinTask< Long> result = exec. submit ( sumThread) ;
System. out. println ( "最后的结果是:" + result. get ( ) ) ;
}
}
class SumThread extends RecursiveTask < Long> {
private static final int THRESHOLD= 50 ;
private List< Integer> list;
private int start;
private int end;
public SumThread ( List< Integer> list) {
this . list = list;
this . start= 0 ;
this . end= list. size ( ) ;
}
public SumThread ( List< Integer> list, int start, int end) {
this . list = list;
this . start = start;
this . end = end;
}
protected Long compute ( ) {
long sum= 0 ;
if ( ( end- start) < THRESHOLD) {
for ( int i= start; i< end; i++ ) {
sum+= list. get ( i) ;
}
System. out. println ( "子任务" + Thread. currentThread ( ) . getName ( ) + "执行完成" ) ;
} else {
ArrayList< SumThread> sumThreads= new ArrayList < SumThread> ( ) ;
int taskNum= end/ ( THRESHOLD- 1 ) + ( end% ( THRESHOLD- 1 ) > 0 ? 1 : 0 ) ;
int endPos= THRESHOLD- 1 ;
int startPos= 0 ;
for ( int i= 0 ; i< taskNum; i++ ) {
SumThread sumThread= new SumThread ( list, startPos, endPos) ;
sumThreads. add ( sumThread) ;
sumThread. fork ( ) ;
startPos+= THRESHOLD- 1 ;
endPos= ( endPos+ THRESHOLD- 1 ) > end? end: ( endPos+ THRESHOLD- 1 ) ;
}
for ( SumThread s: sumThreads) {
sum+= s. join ( ) ;
}
}
return sum;
}
}
子任务ForkJoinPool- 1 - worker- 2 执行完成
子任务ForkJoinPool- 1 - worker- 11 执行完成
子任务ForkJoinPool- 1 - worker- 4 执行完成
子任务ForkJoinPool- 1 - worker- 13 执行完成
子任务ForkJoinPool- 1 - worker- 13 执行完成
子任务ForkJoinPool- 1 - worker- 6 执行完成
子任务ForkJoinPool- 1 - worker- 11 执行完成
子任务ForkJoinPool- 1 - worker- 13 执行完成
子任务ForkJoinPool- 1 - worker- 4 执行完成
子任务ForkJoinPool- 1 - worker- 15 执行完成
子任务ForkJoinPool- 1 - worker- 13 执行完成
子任务ForkJoinPool- 1 - worker- 8 执行完成
子任务ForkJoinPool- 1 - worker- 10 执行完成
子任务ForkJoinPool- 1 - worker- 11 执行完成
子任务ForkJoinPool- 1 - worker- 2 执行完成
子任务ForkJoinPool- 1 - worker- 6 执行完成
子任务ForkJoinPool- 1 - worker- 8 执行完成
子任务ForkJoinPool- 1 - worker- 1 执行完成
子任务ForkJoinPool- 1 - worker- 13 执行完成
子任务ForkJoinPool- 1 - worker- 15 执行完成
子任务ForkJoinPool- 1 - worker- 4 执行完成
最后的结果是:4572
API说明:
构造器
源码public ForkJoinPool ( int parallelism,
ForkJoinWorkerThreadFactory factory,
UncaughtExceptionHandler handler,
boolean asyncMode) {
this ( checkParallelism ( parallelism) ,
checkFactory ( factory) ,
handler,
asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
"ForkJoinPool-" + nextPoolId ( ) + "-worker-" ) ;
checkPermission ( ) ;
}
parallelism:并行数,默认为CPC的核心线程数,最小为1; factory:线程工厂; handler 默认为null,处理任务时出现的异常情况处理类; asyncMode:是否为异步模式,默认为false,为同步时采用的是先进后出原则,而异步时则是先进先出原则进行。异步时就不能通过join获取到对应的结果集可根据实际情况进行使用。 执行:
ForkJoinPool提供了excute和submit两个执行方法,submit用于返回执行的结果,ForkJoin提供了对Runnable、Callable以及ForkJoinTask的三种参数形式的执行,这里就说一下关于ForkJoinTask的参数,ForkJoinTask的抽象子类:RecursiveTask和RecursiveAction,RecursiveTask代表该工作任务有具体的返回值,而RecursiveAction没有具体的返回值。 结构原理:
工作窃取算法:工作窃取算法指的一个线程到另一个线程的队列去窃取任务来进行执行,其优势在于,当一个线程执行完成自己的工作队列后一般情况下就会等待其他线程执行完成在进行返回,而工作窃取算法则使得处于等待状态的线程去为完成工作的线程队列中去窃取队列,而为了防止线程之间因为竞争同一工作而耗费资源,所以窃取的一方则通过队列的某端获取工作任务,而被窃取的线程永远从队列头部获取工作任务,而这样的对垒称为双端队列。但缺点在于当队列中只存在一个任务时,就会出现线程的竞争。 ForkJoinPool中采用的hash数组+双端队列的结构存放任务,在ForkJoinPool中的WorkQueue[] workQueues 代表的就是hash数组,该数组的长度是2的指数,且支持扩容;workQueues内部装的就是工作任务,其内部又将任务拆分为外部任务和内部任务,如像excute、submit提交的任务都称为外部任务,内部任务则时通过fork/join方法产生的。ForkJoin将外部任务和内部任务进行分离,外部任务会利用Thread内部的随机probe值映射hash数组的偶数槽位的提交队列中,这种队列使用的是通过数据加以实现的双端队列;而内部的工作任务在映射到数组的奇数位上。之后每个工作任务所产生的子工作任务也会自动分配到自己所在的任务队列中。而我们上面提出的工作窃取算法。当线程A执行完自己的工作队列后就会去窃取线程B的工作队列中的任务,如果该任务又拆分了许多工作任务,当线程B完成自己的工作队列后,发现线程A窃取了自己的工作队列,且有子任务队列没有执行完毕,则又会从线程A中窃取任务,此工作机制被称为互助机制。