一、异步线程最开始使用
这里橙线有使用到组合模式
所以可以看到开启线程的三种方法
1.继承Thread,实现其run方法
2.由于组合模式,给Thread构造器传入Runnable
即:new Thread(new Runnable{。。。});
3.new Thread(new FutureTask(new Callable(){。。。 }))
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask future = new FutureTask<String>(new Callable<String>() {
public String call() throws Exception {
//模拟需要计算或其他耗时的操作
TimeUnit.SECONDS.sleep(3);
return "我是返回的结果...";
}
});
//使用线程池
ExecutorService executorService = Executors.newFixedThreadPool(3);
executorService.submit(future);
//获取执行的结果
String ret = (String) future.get();
System.out.println(ret);
}
说明:
1.Executor的唯一方法execute无返回值,所以拓展出了ExecutorService接口
2.Runnable的唯一方法run无返回值,所以拓展出Callable接口
线程池
Q:为什么要用线程
异步加速
Q:为什么要用线程池
防止百万请求,每次生成一个线程,资源耗尽
四种拒绝策略:
AbortPolicy(默认):直接抛出RejectedExecutionException异常阻止系统正常运行。
CallerRunsPolicy:直接让原线程执行,退化为同步
DiscardoldestPolicy:丢弃最早任务,加入新任务
DiscardPolicy:直接丢弃任务,不予任何处理也不抛出异常。如果允许任务丢失,这是最好的一种方案。
这四种内置拒绝策略均实现了RejectExecutionHandler接口
Executors常见线程池:
1.SingleThreadExecutor
说明:
1)链式无界阻塞队列,不丢弃任务,所以可能会导致OOM
2.FixThreadPool
说明:
1)和前者类似,核心线程数等于最大线程数,所以3,4参数失效
2)采用无界队列,不会丢失任务,可能会OOM
3.CachedThreadPool
说明:
1)只有非核心线程,并且线程数最大为2^32-1,可能会OOM
2)60s,杀死空闲非核心线程
3)SynchronousQueue,这个阻塞队列没有存储空间,意味需要立马有线程执行。
4.ScheduledThreadPoolExecutor
说明:
1)该线程池执行器,可用于定时重复完成任务
2)线程数最大为2^32-1,可能会OOM
3)DelayedWorkQueue,数组实现,有界阻塞,优先队列
自定义线程池
背景:由于以上这四种都有可能造成OOM,并且阿里明确指出禁止使用默认线程池,那么自定义线程池尤为重要。
自定义的规则如下:
由于线程是为了最大程度利用cpu资源,所以需要考虑系统架构的是Cpu密集型还是IO密集型
单核心Cpu总线数量为8
1.IO密集型如下
2.计算密集型
最终解决方案:
说明:
1.积压长度,通过压力测试。
如:该业务允许10s内返回结果,假设该业务耗时1s,通过测试不同队列长度,来保证10s内所有任务的完成。
二、Java 8 特性 CompletableFuture
相比于Future接口有哪些好处呢?
1.可以捕获异常
2.可以串行执行
3.可以组合编排