自定义线程池:
/**
* 自定义线程池
*/
public class UserThreadFactory implements ThreadFactory {
private final String namePrefix;
private final AtomicInteger nextId = new AtomicInteger(1);
public UserThreadFactory(String whatFeatOfGroup) {
namePrefix = "From UserThreadFactory's "+whatFeatOfGroup+" Worker!";//线程名字
}
@Override
public Thread newThread(Runnable task) {
String name = namePrefix+nextId.getAndIncrement();//线程名字+CAS
Thread thread = new Thread(null,task,name,0);
System.out.println(thread.getName());
return thread;
}
}
线程池:
线程池
-
目前JDK自带两种:
1.ThreadPoolExecutor:普通的(背过)
多个线程维护一个队列;
1.corePoolSize,核心线程;
2.maximumPoolSize,最大线程;
3.keepAliveTime,生存时间,很长时间不干活了,归还操作系统;
4.TimeUnit,生存时间单位,毫秒,纳秒,秒可以自己定义;
5.BlockingQueue,任务队列,各种Queue都可以往进放;
6.ThreadFactory,线程工厂,产生线程的;
1.指定了group,制定了线程的名字;
2.绝对不是守护线程;
7.RejectedExecutionHandler,拒绝策略,线程池忙,队列满,可以拒绝,拒绝策略可以自定义,JDK提供了四种:
1.Abort;抛异常
2.Discard; 扔掉,不抛异常
3.DiscardOldest;扔掉排队时间最久的
4.CallerRuns;谁提交,谁调用,调用者处理任务2.ForkJoinPool:Fork分叉,最后结果汇总join
每个线程都有自己的队列
ThreadPoolExecutor源码解析
- 常用变量的解释
- 构造方法
- 提交执行task的过程
- addWorker源码解析
底层都是ThreadPool线程池
ThreadPoolExecutor
- SingleThreadPool 一个线程的线程池
1.只有一个线程;
Q:为什么要有单线程的线程池?
A:1.线程池是由任务队列的;
2.生命周期管理;
ExecutorService executorService = Executors.newSingleThreadExecutor();
//源码
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
- CachedThreadPool 弹性的线程池,来一个启动一个
ExecutorService executorService1 = Executors.newCachedThreadPool();
//源码
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
//没有核心线程数
//SynchronousQueue
//来一个新的任务必须马上执行,没有线程空的就立马new一个新的线程
- FixedThreadPool 并行执行,固定多少个线程的线程池
ExecutorService executorService2 = Executors.newFixedThreadPool(5);
//源码
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
//是没有最大线程数的,核心线程数=最大线程数,所以不需要回收
Q:什么时候用CachedThreadPool,什么时候用FixedThreadPool?
A:任务忽高忽低,用CachedThreadPool;平稳用FixedThreadPool;
- ScheduledThreadPool 定时任务线程池
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
//源码
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
DelayedWorkQueue 指定隔多长时间之后开始执行;
用的也不多,复杂的话就直接用定时任务框架 qyartz cron;
面试题:一个闹钟服务,订阅这个服务的很多,10E人,怎么优化?
分而治之,主服务器把请求转发不同的边缘服务,用队列存储,线程池消化;
并行和并发的区别
并发:任务提交
并行:任务执行
并行是并发的子集;
ForkJoinPool
-
WorkStealingPool
原理:
1.多个work Queue,每一个线程维护一个一个队列
2.采用work stealing算法里边就是new了一个ForkJoinPool
ExecutorService executorService3 = Executors.newWorkStealingPool();
源码:
public static ExecutorService newWorkStealingPool() {
return new ForkJoinPool
(Runtime.getRuntime().availableProcessors(),
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
}
-
ForkJoinPool
原理:
1.将一个大任务切换成一个个小任务;
2.将结果在进行汇总;代码:
1.创建一个ForkJoinPool对象,初始化线程个数
ForkJoinPool pool = new ForkJoinPool(3);
2.调用pool的invork()方法,传入一个ForkJoinTask调度器,ForkJoinTask代表一个可并行合并的任务;
3.ForkJoinTask有两个抽象子类,
RecursiveTask:代表有返回值的任务
RecursiveAction:代表无返回值的任务
4.重写RecursiveTask类中的compure方法,可以实现任务分叉,
比如:RecursiveTask1任务与RecursiveTask2任务
分叉:
RecursiveTask1.fork();
RecursiveTask2.fork();
合并:
int a = RecursiveTask1.join();
int b = RecursiveTask2.join();
返回:
return a+b;
没有返回值的继承 RecursiveAction
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cGKEqgvq-1627494216524)(http://note.youdao.com/yws/res/7424/WEBRESOURCE1871ec8a1bd77d829d4b03aa45c7b277)]
有返回值的继承 RecursiveTask<返回值>