在使用线程池的时候,我们可以使用JDK提供的缓存线程池,这也是经常用到的,如下:
ExecutorService executorService = Executors.newCachedThreadPool();
也可以使用固定线程池,如下:
ExecutorService executorService = Executors.newFixedThreadPool(count);
有时候,我们需要自定义适合自己需要的线程池:ThreadPoolExecutor , 代码如下:
自定义线程池
package com.test1.threads;
import java.lang.reflect.Field;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* ThreadPoolExecutor
当一个任务通过execute(Runnable)方法欲添加到线程池时:
如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。
如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。
如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务
* */
public class MyExecutorThreadPool {
static void log(String msg) {
System.out.println(System.currentTimeMillis() + " -> " + msg);
}
static int getThreadRunState(ThreadPoolExecutor pool)throws Exception {
// Field field = ThreadPoolExecutor.class.getDeclaredField("runState");
// field.setAccessible(true);
// int s = field.getInt(pool);
return 1;
}
public static void main(String[] args) throws Exception {
//阻塞队列的固定长度为1
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(1);
/*
DiscardPolicy 表示直接放弃,也不抛出异常。打印如下:
1431932733129 -> before sleep
1431932733129 -> run task: 0 -> pool-1-thread-1
1431932734129 -> run over: 0 -> pool-1-thread-1
1431932734129 -> run task: 1 -> pool-1-thread-1
1431932735129 -> run over: 1 -> pool-1-thread-1
1431932737129 -> before shutdown()
1431932737130 -> after shutdown(),pool.isTerminated=true
1431932737130 -> now,pool.isTerminated=true, state=1
* */
RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();
/*
AbortPolicy 表示当有多余的任务时,直接放弃且抛出异常。打印如下:
Exception in thread "main" 1431932635036 -> run task: 0 -> pool-1-thread-1
java.util.concurrent.RejectedExecutionException: Task com.test1.threads.TaskRunnable@42ff665a rejected from java.util.concurrent.ThreadPoolExecutor@27abcd5e[Running, pool size = 1, active threads = 1, queued tasks = 1, completed tasks = 0]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.reject(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.execute(Unknown Source)
at com.test1.threads.MyExecutorThreadPool.main(MyExecutorThreadPool.java:129)
1431932636036 -> run over: 0 -> pool-1-thread-1
1431932636036 -> run task: 1 -> pool-1-thread-1
1431932637036 -> run over: 1 -> pool-1-thread-1
* */
// handler = new ThreadPoolExecutor.AbortPolicy();
/*
DiscardOldestPolicy 表示抛弃最旧的任务,从task1到task8都被抛弃,最后加入的task9会被执行。打印如下:
1431931268334 -> before sleep
1431931268334 -> run task: 0 -> pool-1-thread-1
1431931269334 -> run over: 0 -> pool-1-thread-1
1431931269334 -> run task: 9 -> pool-1-thread-1
1431931270334 -> run over: 9 -> pool-1-thread-1
1431931272335 -> before shutdown()
1431931272336 -> after shutdown(),pool.isTerminated=false
1431931272336 -> now,pool.isTerminated=true, state=1
*/
// handler = new ThreadPoolExecutor.DiscardOldestPolicy();
/*
* CallerRunsPolicy 表示,剩下的任务由当前子线程的调用者线程去处理。
* 在本例中, 线程池中的线程的调用者为主线程,也就是main函数。如果另外新建一个线程,并用新建的
线程来启动线程池中的线程,则线程池中的线程的调用者为新建的那个线程。如下:
new Thread(new Runnable() {
@Overried
public void run() {
ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 1, 0, TimeUnit.MINUTES, queue);
.....
for(.....) {
}
}
}).start();
// 打印如下
1431930356817 -> run task: 2 -> Thread-0
1431930356817 -> run task: 0 -> pool-1-thread-1
1431930357818 -> run over: 0 -> pool-1-thread-1
1431930357818 -> run over: 2 -> Thread-0
1431930357818 -> run task: 3 -> Thread-0
1431930357818 -> run task: 1 -> pool-1-thread-1
1431930358818 -> run over: 3 -> Thread-0
1431930358818 -> run over: 1 -> pool-1-thread-1
1431930358819 -> run task: 5 -> Thread-0
1431930358819 -> run task: 4 -> pool-1-thread-1
1431930359819 -> run over: 4 -> pool-1-thread-1
1431930359819 -> run over: 5 -> Thread-0
1431930359819 -> run task: 7 -> Thread-0
1431930359819 -> run task: 6 -> pool-1-thread-1
1431930360820 -> run over: 6 -> pool-1-thread-1
1431930360820 -> run over: 7 -> Thread-0
1431930360820 -> run task: 9 -> Thread-0
1431930360820 -> run task: 8 -> pool-1-thread-1
1431930361820 -> run over: 8 -> pool-1-thread-1
1431930361820 -> run over: 9 -> Thread-0
当调用者是main线程的时候,打印如下:
1431931124052 -> run task: 2 -> main
1431931124052 -> run task: 0 -> pool-1-thread-1
1431931125052 -> run over: 2 -> main
1431931125052 -> run task: 3 -> main
1431931125052 -> run over: 0 -> pool-1-thread-1
1431931125052 -> run task: 1 -> pool-1-thread-1
1431931126052 -> run over: 1 -> pool-1-thread-1
1431931126052 -> run over: 3 -> main
1431931126053 -> run task: 4 -> pool-1-thread-1
1431931126053 -> run task: 5 -> main
1431931127053 -> run over: 5 -> main
1431931127053 -> run over: 4 -> pool-1-thread-1
1431931127053 -> run task: 6 -> pool-1-thread-1
1431931127053 -> run task: 8 -> main
1431931128053 -> run over: 6 -> pool-1-thread-1
1431931128053 -> run task: 7 -> pool-1-thread-1
1431931128053 -> run over: 8 -> main
1431931128053 -> before sleep
1431931129053 -> run over: 7 -> pool-1-thread-1
1431931129053 -> run task: 9 -> pool-1-thread-1
*/
// handler = new ThreadPoolExecutor.CallerRunsPolicy();
/*
* //自定义的固定长度的线程池,线程池中的线程总数为1
pool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
参数解释如下:
corePoolSize: 如果池中的实际线程数小于corePoolSize,无论是否其中有空闲的线程,
都会给新的任务产生新的 线程;
如果池中的线程数>corePoolSize and <maximumPoolSize,而又有空闲线程,就给新任务使用
空闲线程,如没有空闲线程,则产生新线程。
maximumPoolSize:线程池中的最大线程数。
如果池中的线程数=maximumPoolSize,则有空闲线程使用空闲线程,否则新任务放入workQueue。
(线程的空闲只有在workQueue中不再有任务时才成立);
当线程空闲时间达到keepAliveTime,该线程会退出,直到线程数量等于corePoolSize。
如果allowCoreThreadTimeout设置为true,则所有线程均会退出直到线程数量为0。
keepAliveTime:当线程池中的线程数大于corePoolSize的时候,那么空闲线程在等待keepAliveTime后,如果还没有新任务
到来,那么多余的空闲线程将被终止,直到线程数等于corePoolSize,此时allowCoreThreadTimeout=false;
unit:时间单元,可以指定时间的单位。
workQueue:任务缓存队列。见最上面的描述。
另外:当corePoolSize = maximumPoolSize 的时候,就是个固定线程池。可以通过查看源码看看FixedPool等。
* */
ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 1, 0, TimeUnit.MINUTES, queue);
pool.setRejectedExecutionHandler(handler);
for(int i=0; i < 10; i++) {
final int c = i;
pool.execute(new TaskRunnable(c));
}
log("before sleep");
Thread.sleep(4000L);
log("before shutdown()");
pool.shutdown();
log("after shutdown(),pool.isTerminated=" + pool.isTerminated());
pool.awaitTermination(1000L, TimeUnit.SECONDS);
log("now,pool.isTerminated=" + pool.isTerminated() + ", state=" + getThreadRunState(pool));
}
}
// 任务类,实现Runnable接口。
package com.test1.threads;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TaskRunnable implements Runnable {
private final int index;
protected TaskRunnable(int index) {
this.index = index;
}
static void log(String msg) {
System.out.println(System.currentTimeMillis() + " -> " + msg);
}
@Override
public void run() {
log("run task: " + index + " -> " + Thread.currentThread().getName());
try {
Thread.sleep(1000L);
} catch (Exception e) {
e.printStackTrace();
}
log("run over: " + index + " -> " + Thread.currentThread().getName());
}
}