【java多线程学习之四】线程池原理以及获取线程结果的三种方式
这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战
1 线程池的工作原理以及7个参数
线程池的工作原理和7个参数(京东物流、美团充电宝一面、中信银行一面、美团外卖一面、58用户平台一面、轻松集团)
1.1 7个参数
- corePoolSize:线程池核心线程数量
- maximumPoolSize:线程池最大线程数量
- keepAliverTime:当活跃线程数大于核心线程数时,空闲的多余线程最大存活时间
- unit:存活时间的单位
- workQueue:存放任务的队列
- threadFactory:创建线程的工厂
- handler:超出线程范围和队列容量的任务的处理程序 每个值为什么这么设置?
1.2 工作原理
例子: 核心线程数量为5个;全部线程数量为10个;工作队列的长度为5。
刚开始都是在创建新的线程,达到核心线程数量5个后,新的任务进来后不再创建新的线程,而是将任务加入工作队列;
任务队列到达上线5个后,新的任务又会创建新的普通线程,直到达到线程池最大的线程数量10个;
后面的任务则根据配置的饱和策略来处理。我们这里没有具体配置,使用的是默认的配置AbortPolicy:直接抛出异常。
当当前任务小于最大线程数的时候,线程资源会保持核心线程池个数的线程,其他超过的线程资源在存活时间时间之后会被回收。
1.3 拒绝策略
1、AbortPolicy:直接抛出异常 2、CallerRunsPolicy:只用调用所在的线程运行任务 3、DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。 4、DiscardPolicy:不处理,丢弃掉。
1.4 代码
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 线程池测试
* 使用丢弃策略处理多余线程,不管多余线程
*/
public class ThreadPoolTest2 {
public static void main(String[] args) {
LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(5);
// 丢弃策略,多余的线程直接不处理,丢弃
RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();
// 创建线程池 5 10 60s
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 10, 60,
TimeUnit.SECONDS, queue, handler);
for (int i = 1; i <= 16; i++) {
threadPool.execute(new Thread(new ThreadTest(), "Thread".concat(i + "")));
System.out.println("线程池中活跃的线程数: " + threadPool.getPoolSize());
if (queue.size() > 0) {
System.out.println("-------队列中阻塞的线程数" + queue.size());
}
}
threadPool.shutdown();
}
}
输出:
com.geniu.concurrent.ThreadPool.ThreadPoolTest2
线程池中活跃的线程数: 1
线程池中活跃的线程数: 2
线程池中活跃的线程数: 3
线程池中活跃的线程数: 4
线程池中活跃的线程数: 5
线程池中活跃的线程数: 5
-------队列中阻塞的线程数1
线程池中活跃的线程数: 5
-------队列中阻塞的线程数2
线程池中活跃的线程数: 5
-------队列中阻塞的线程数3
线程池中活跃的线程数: 5
-------队列中阻塞的线程数4
线程池中活跃的线程数: 5
-------队列中阻塞的线程数5
线程池中活跃的线程数: 6
-------队列中阻塞的线程数5
线程池中活跃的线程数: 7
-------队列中阻塞的线程数5
线程池中活跃的线程数: 8
-------队列中阻塞的线程数5
线程池中活跃的线程数: 9
-------队列中阻塞的线程数5
线程池中活跃的线程数: 10
-------队列中阻塞的线程数5
线程池中活跃的线程数: 10
-------队列中阻塞的线程数5
源码地址:github.com/zhongsb/Jav… 参考:www.cnblogs.com/dongguacai/…
2 三种获取线程执行结果的方法
2.1、Callable 线程
public class FetchAdTask implements Callable<Ad> {
@Override
public Ad call() throws Exception {
System.out.println("fetch task");
sleep(1000L);
return null;
}
}
2.2、使用Future,包括 FutureTask、CompletableFuture
CompletableFuture.get();
Future 的优点:可以对任务设置时限,如果超时了,可以取消,然后返回一个默认结果,防止 某一个任务出现问题,导致系统出现问题。
f.get(timeLeft, TimeUnit.NANOSECONDS);
或者通过 invokeAll() 返回限定时间范围内的所有任务的结果。
executor.invokeAll(tasks, time, unit);
CompletableFuture, 使用 supplyAsync 方法提交线程,使用 get 方法获取结果。
CompletableFuture<Integer> task3 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务3, 线程名字" + Thread.currentThread().getName());
try {
sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 3;
});
CompletableFuture.allOf(task1, task2, task3, task4);
System.out.println("end: " + new Date());
task1.get();
2.3、使用 CompletionService,
CompletionService.take();
例子
private static final long TIME_BUDGET = 100L;
private static final Ad DEFAULT_AD = new Ad();
private final ExecutorService executor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors() + 1,
Runtime.getRuntime().availableProcessors() + 1, 0L,
TimeUnit.MILLISECONDS, new LinkedBlockingQueue(1000));
public static void main(String[] args) {
try {
Test616LimitedTimeTask task = new Test616LimitedTimeTask();
task.test();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 测试超时取消
*
* @throws InterruptedException
*/
void test() throws InterruptedException {
Ad ad = null;
long endNanos = System.nanoTime() + TIME_BUDGET;
Future<Ad> f = executor.submit(new FetchAdTask());
try {
long timeLeft = endNanos - System.nanoTime();
// 增加参数 超时时间和超时时间的单位
ad = f.get(timeLeft, TimeUnit.NANOSECONDS);
} catch (ExecutionException e) {
ad = DEFAULT_AD;
} catch (TimeoutException e) {
// 超时,取消任务
ad = DEFAULT_AD;
System.out.println("超时取消");
f.cancel(true);
}
}
优点:多个 CompletionService 可以共享一个 Executor,因此可以创建一个对于特定计算私有, 又能共享一个公共 Executor 的 ExecutorCompletionService。