1.线程池与线程性能对比
在单线程情况下处理任务的速度和用线程池对比性能有很大提升,线程池内部可以线程复用,在线程处理完任务以后可以回到线程池,处理其他任务,这样大大减少了线程销毁和创建的时间。
java自带的几种线程池:
ExecutorService executorService = Executors.newCachedThreadPool(); ExecutorService executorService1 = Executors.newFixedThreadPool(100); ExecutorService executorService2 = Executors.newSingleThreadExecutor(); ExecutorService executorService3 = Executors.newScheduledThreadPool(10);上面的线程池看构造参数都是用ThreadPoolExecutor创建,只是使用的参数不同。
newCachedThreadPool使用的构造方法:对应参数(核心线程数,最大线程数,线程存活时间,线程存活时间单位,队列),newCachedThreadPool只有0个核心线程,临时线程数可以无限大,所以它的执行效率很高,SynchronousQueue是一个典型的生产者消费者模式,相当于一个外包公司。
new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>())newCachedThreadPool使用的构造方法:核心线程数和临时线程数都是自定义的,LinkedBlockingQueue队列是一个无界阻塞队列,相当于可以无限等待任务处理,但是效率很低。相当于一个国企。 new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())newSingleThreadExecutor使用的构造方法:核心线程数和临时线程数都是1,相当于1个人处理无数的任务,效率在很快能处理完任务的时候很快,但是在需要处理任务很慢的时候就会显得效率很低。相当于一个私企,什么都是一个人干。 new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()))最有可能出现OOM的线程池:newCachedThreadPool,里面不是无界队列,达到内存的最大值后会报OOM情况
前面三种情况阿里规范都不推荐,但在不是能达到内存top值的业务中上面三种都可以用,阿里推荐自定义线程池ThreadPoolExecutor
1.1 线程池对比实战
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadDemo {
public static void main(String[] args) {
//定义3个线程池
ExecutorService executorService = Executors.newCachedThreadPool();//很快
ExecutorService executorService1 = Executors.newFixedThreadPool(100);//不快不慢
ExecutorService executorService2 = Executors.newSingleThreadExecutor();//最慢
//定义100个任务给线程池处理对比处理性能
long begin = System.currentTimeMillis();
for(int i=0;i<100;i++){
executorService2.submit(new Task());
}
executorService.shutdown();
long end = System.currentTimeMillis();
System.out.println("处理时间:"+(end-begin)/1000+"秒");
}
}
class Task implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"处理完任务");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
1.2 ThreadPoolExecutor实战
/**
* 第31个任务会拒绝任务
*/
public class ThreadDemo {
public static void main(String[] args) {
//定义ThreadPoolExecutor
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 30, 0, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(10));
//定义100个任务给线程池处理对比处理性能
long begin = System.currentTimeMillis();
for(int i=0;i<100;i++){
threadPoolExecutor.submit(new Task());
}
threadPoolExecutor.shutdown();
long end = System.currentTimeMillis();
System.out.println("处理时间:"+(end-begin)/1000+"秒");
}
}
class Task implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"处理完任务");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
1.3 面试题1:自定义线程池参数
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {corePoolSize:核心线程数
int maximumPoolSize:最大线程数
long keepAliveTime:临时线程存活时间
TimeUnit unit:临时线程存活单位
BlockingQueue<Runnable> workQueue:任务队列
ThreadFactory threadFactory:一般自定义工厂类
RejectedExecutionHandler handler:拒绝策略,定义的有4种,一般我们可以自定义拒绝策略
AbortPolicy:默认抛出RejectedExecutionException拒绝任务 DiscardPolicy:抛弃任务 DiscardOldestPolicy:通过队列结构抛出最老的任务 CallerRunsPolicy:由调用execute方法的线程执行任务
1.4 面试题线程池源码分析执行原理图(TODO)
1.5 面试题submit()与execute方法区别(TODO)
submit与execute的区别:在线程中存在一个提交优先级和执行优先级的概念,提交优先级高于执行优先级。 1. execute方法在submit方法中。 2. submit方法会返回Future泛型函数,而execute不返回
1.6 面试题offer()与add()区别
add和offer都是任务队列添加任务的方法,区别add方法不抛出异常,而offer会抛出中断异常,这是他们唯一的区别。
1.7 newScheduledThreadPool(TODO)
1.7.1 newScheduledThreadPool实战(TODO)
1.7.2 源码分析(TODO)
1.8 自定义拒绝策略
自定义拒绝策略两种方法:
//自定义拒绝策略 RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler() { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { System.out.println("自定义拒绝策略,可以存入数据库"); } };第二种:实现RejectedExecutionHandler接口重写rejectedExecution方法。
import java.util.concurrent.*;
/**
* 第31个任务会拒绝任务
*/
public class ThreadDemo {
public static void main(String[] args) {
//自定义拒绝策略
RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println("自定义拒绝策略,可以存入数据库");
}
};
//定义ThreadPoolExecutor
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 30, 0, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(10),rejectedExecutionHandler);
//定义100个任务给线程池处理对比处理性能
long begin = System.currentTimeMillis();
for(int i=0;i<100;i++){
threadPoolExecutor.submit(new Task());
}
threadPoolExecutor.shutdown();
long end = System.currentTimeMillis();
System.out.println("处理时间:"+(end-begin)/1000+"秒");
}
}
class Task implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"处理完任务");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}