JAVA高效编程七(线程池)
简介
简单线程池的设计
线程池参数与处理流程
线程池可选择的阻塞队列
阻塞队列:当队列满时,向队列中插入元素的线程会阻塞,直到队列变成不满。当队列为空时,从队列中获取元素的线程会阻塞,直到队列变成非空。
同步移交队列:不存储元素,每个插入的操作必须等到另一个线程去调用移除操作,才能成功,否则插入的操作一直处于阻塞状态。
public class QueueTest {
@Test
public void arrayBlockingQueue() throws InterruptedException {
/**
* 基于数组的有界阻塞队列,队列容量为10
*/
ArrayBlockingQueue queue =
new ArrayBlockingQueue<Integer>(10);
// 循环向队列添加元素
for (int i = 0; i < 20; i++) {
queue.put(i);
System.out.println("向队列中添加值:" + i);
}
}
@Test
public void linkedBlockingQueue() throws InterruptedException {
/**
* 基于链表的有界/无界阻塞队列,队列容量为10
*/
LinkedBlockingQueue queue =
new LinkedBlockingQueue<Integer>();
// 循环向队列添加元素
for (int i = 0; i < 20; i++) {
queue.put(i);
System.out.println("向队列中添加值:" + i);
}
}
@Test
public void test() throws InterruptedException {
/**
* 同步移交阻塞队列
*/
SynchronousQueue queue = new SynchronousQueue<Integer>();
// 插入值
new Thread(() -> {
try {
queue.put(1);
System.out.println("插入成功");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
// 删除值
/*
new Thread(() -> {
try {
queue.take();
System.out.println("删除成功");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
*/
Thread.sleep(1000L * 60);
}
}
线程池可选择的饱和策略
/**
* 类名称:PolicyTest
* ********************************
* <p>
* 类描述:饱和策略
*
* @author zhangxiaoxi
* @date 上午10:15
*/
public class PolicyTest {
/**
* 线程池
*/
private static ThreadPoolExecutor executor =
new ThreadPoolExecutor(
// 核心线程数和最大线程数
2, 3,
// 线程空闲后的存活时间
60L, TimeUnit.SECONDS,
// 有界阻塞队列
new LinkedBlockingQueue<Runnable>(5));
/**
* 任务
*/
class Task implements Runnable {
/**
* 任务名称
*/
private String taskName;
public Task(String taskName) {
this.taskName = taskName;
}
@Override
public void run() {
System.out.println("线程[ " + Thread.currentThread().getName()
+ " ]正在执行[ " + this.taskName + " ]任务...");
try {
Thread.sleep(1000L * 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程[ " + Thread.currentThread().getName()
+ " ]已执行完[ " + this.taskName + " ]任务!!!");
}
}
/**
* 线程池的执行过程
*
* 2个核心线程
* 5个任务的队列
* 3个最大线程:1个线程可用
*
* 前2个任务,会占用2个核心线程
* 第3个到第7个任务,会暂存到任务队列中
* 第8个任务,会启动最大线程,去执行
* 第9个任务,没有线程可以去执行~~~
*/
/**
* 终止策略
* TODO 抛出异常,拒绝任务提交
*/
@Test
public void abortPolicyTest() {
// 设置饱和策略为 终止策略
executor.setRejectedExecutionHandler(
new ThreadPoolExecutor.AbortPolicy());
for (int i = 1; i <= 10; i++) {
try {
// 提交10个线程任务
executor.execute(new Task("线程任务" + i));
} catch (Exception e) {
System.err.println(e);
}
}
// 关闭线程池
executor.shutdown();
}
/**
* 抛弃策略
* TODO 直接丢弃掉新提交的任务
*/
@Test
public void discardPolicyTest() {
// 设置饱和策略为 抛弃策略
executor.setRejectedExecutionHandler(
new ThreadPoolExecutor.DiscardPolicy());
for (int i = 1; i <= 10; i++) {
try {
// 提交10个线程任务
executor.execute(new Task("线程任务" + i));
} catch (Exception e) {
System.err.println(e);
}
}
// 关闭线程池
executor.shutdown();
}
/**
* 抛弃旧任务策略
* TODO 丢弃掉任务队列中的旧任务,暂存新提交的任务
*/
@Test
public void discardOldestPolicyTest() {
// 设置饱和策略为 抛弃旧任务策略
executor.setRejectedExecutionHandler(
new ThreadPoolExecutor.DiscardOldestPolicy());
for (int i = 1; i <= 10; i++) {
try {
// 提交10个线程任务
executor.execute(new Task("线程任务" + i));
} catch (Exception e) {
System.err.println(e);
}
}
// 关闭线程池
executor.shutdown();
}
/**
* 调用者运行策略
* TODO 借用主线程来执行多余任务
*/
@Test
public void callerRunsPolicyTest() {
// 设置饱和策略为 调用者运行策略
executor.setRejectedExecutionHandler(
new ThreadPoolExecutor.CallerRunsPolicy());
for (int i = 1; i <= 10; i++) {
try {
// 提交10个线程任务
executor.execute(new Task("线程任务" + i));
} catch (Exception e) {
System.err.println(e);
}
}
// 关闭线程池
executor.shutdown();
}
/**
* 单元测试执行完,主线程等待100秒。防止主线程退出,看不到线程的执行结果
* @throws InterruptedException
*/
@After
public void after() throws InterruptedException {
Thread.sleep(1000L * 100);
}
}
线程池的执行示意图
常用线程池
向线程池提交任务
public class RunTest {
@Test
public void submitTest()
throws ExecutionException, InterruptedException {
// 创建线程池
ExecutorService threadPool =
Executors.newCachedThreadPool();
/**
* 利用submit方法提交任务,接收任务的返回结果
*/
Future<Integer> future = threadPool.submit(() -> {
Thread.sleep(1000L * 10);
return 2 * 5;
});
/**
* 阻塞方法,直到任务有返回值后,才向下执行
*/
Integer num = future.get();
System.out.println("执行结果:" + num);
}
@Test
public void executeTest() throws InterruptedException {
// 创建线程池
ExecutorService threadPool =
Executors.newCachedThreadPool();
/**
* 利用execute方法提交任务,没有返回结果
*/
threadPool.execute(() -> {
try {
Thread.sleep(1000L * 10);
} catch (InterruptedException e) {
e.printStackTrace();
}
Integer num = 2 * 5;
System.out.println("执行结果:" + num);
});
Thread.sleep(1000L * 1000);
}
}