10.线程池
感谢秦疆老师的JUC并发编程视频,更多了解哔哩哔哩搜索【狂神说Java】。
本文内容源于秦疆老师的JUC并发编程视频教程。给狂神推荐,点赞吧!
线程池
线程池:三大方法、7大参数、4种拒绝策略
池化技术
程序的运行,本质:占用系统的资源!优化资源的使用!=》池化技术
线程池、连接池、内存池、对象池//
池化技术:事先准备好一些资源,有人要用,就来我这里拿,用完之后还给我。
线程池的好处:
- 降低资源的消耗
- 提高响应的速度
- 方便管理
线程复用,可以控制最大并发数,管理线程
线程池:三大方法
阿里巴巴开发手册规范:
代码测试:
package demo7;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//Executors 工具类 3大方法
public class ExecutorsTest1 {
public static void main(String[] args) {
ExecutorService executorService = null;
//单一线程
executorService = Executors.newSingleThreadExecutor();
//创建一个固定的线程池的大小
Executors.newFixedThreadPool(5);
//创建可伸缩的,遇强则强,遇弱则弱
Executors.newCachedThreadPool();
try {
for (int i = 0; i < 10; i++) {
//使用线程池之后,使用线程池来创建线程
executorService.execute(() -> {
System.out.println(Thread.currentThread().getName() + " =>ok");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//线程池用完,程序结束,关闭线程池
executorService.shutdown();
}
}
}
- Executors.newSingleThreadExecutor()
//单一线程
ExecutorService executorService = Executors.newSingleThreadExecutor();
输出:
pool-1-thread-1 =>ok
pool-1-thread-1 =>ok
pool-1-thread-1 =>ok
pool-1-thread-1 =>ok
pool-1-thread-1 =>ok
pool-1-thread-1 =>ok
pool-1-thread-1 =>ok
pool-1-thread-1 =>ok
pool-1-thread-1 =>ok
pool-1-thread-1 =>ok
- Executors.newFixedThreadPool(5)
//创建一个固定的线程池的大小
ExecutorService executorService = Executors.newFixedThreadPool(5);
输出:
pool-1-thread-1 =>ok
pool-1-thread-2 =>ok
pool-1-thread-1 =>ok
pool-1-thread-2 =>ok
pool-1-thread-2 =>ok
pool-1-thread-2 =>ok
pool-1-thread-4 =>ok
pool-1-thread-5 =>ok
pool-1-thread-1 =>ok
pool-1-thread-3 =>ok
- Executors.newCachedThreadPool()
//创建可伸缩的,遇强则强,遇弱则弱
ExecutorService executorService = Executors.newCachedThreadPool();
输出:
pool-1-thread-2 =>ok
pool-1-thread-5 =>ok
pool-1-thread-4 =>ok
pool-1-thread-3 =>ok
pool-1-thread-1 =>ok
pool-1-thread-6 =>ok
pool-1-thread-6 =>ok
pool-1-thread-7 =>ok
pool-1-thread-8 =>ok
pool-1-thread-9 =>ok
七大参数
七大参数
- int corePoolSize, //核心线程池大小
- int maximumPoolSize, //最大核心线程池大小
- long keepAliveTime, //超时了没有人调用就会释放
- TimeUnit unit, //超时单位
- BlockingQueue workQueue, //阻塞队列
- ThreadFactory threadFactory, //线程工厂:创建线程的,一般不用动
- RejectedExecutionHandler handler //拒绝策略
源码分析:
//核心线程数,最大线程数都为 1
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
// nThreads, nThreads, =>newFixedThreadPool(5) 把核心线程数,最大线程数这两个参数都变成5
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
//0, Integer.MAX_VALUE 约等于21亿 OOM
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
//本质ThreadPoolExecutor()
public ThreadPoolExecutor(int corePoolSize, //核心线程池大小
int maximumPoolSize,//最大核心线程池大小
long keepAliveTime,//超时了没有人调用就会释放
TimeUnit unit,//超时单位
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
//this()
public ThreadPoolExecutor(int corePoolSize,//核心线程池大小
int maximumPoolSize,//最大核心线程池大小
long keepAliveTime,//超时了没有人调用就会释放
TimeUnit unit,//超时单位
BlockingQueue<Runnable> workQueue,//阻塞队列
ThreadFactory threadFactory,//线程工厂:创建线程的,一般不用动
RejectedExecutionHandler handler//拒绝策略
) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
自定义线程池
阿里巴巴手册规范:
手动创建线程池
package demo7;
import java.util.concurrent.*;
/**
* 手动创建线程池
* <p>
* int corePoolSize,
* int maximumPoolSize,
* long keepAliveTime,
* TimeUnit unit,
* BlockingQueue<Runnable> workQueue,
* ThreadFactory threadFactory,
* RejectedExecutionHandler handler
*/
public class ExecutorsTest2 {
public static void main(String[] args) {
//自定义线程池
ExecutorService executorService = new ThreadPoolExecutor(
2,
5,
3,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(3),
Executors.defaultThreadFactory(),
// new ThreadPoolExecutor.AbortPolicy() //默认 银行满了,还有人进来,不处理这个人,抛出异常
// new ThreadPoolExecutor.DiscardOldestPolicy()//队列满了, 丢掉任务 ,不会抛出异常
// new ThreadPoolExecutor.CallerRunsPolicy()//哪来的哪去
new ThreadPoolExecutor.DiscardOldestPolicy()//队列满了,尝试和最早的竞争,不会抛出异常
);
try {
//最大承载 = 队列 deque + max
//超出抛出RejectedExecutionException 异常
for (int i = 1; i <= 10; i++) {
executorService.execute(() -> {
System.out.println(Thread.currentThread().getName() + "=>ok");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭线程池
executorService.shutdown();
}
}
}
4种拒绝策略
4种拒绝策略
- new ThreadPoolExecutor.AbortPolicy() //默认的策略 银行满了,还有人进来,不处理这个人,抛出异常
- new ThreadPoolExecutor.CallerRunsPolicy() //哪来的哪去
-
new ThreadPoolExecutor.DiscardOldestPolicy() //队列满了, 丢掉任务 ,不会抛出异常
-
new ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,尝试和最早的竞争,不会抛出异常
源码:
//由调用线程(提交任务的线程)处理该任务
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public CallerRunsPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
//线程池的默认拒绝策略为AbortPolicy,即丢弃任务并抛出RejectedExecutionException异常
public static class AbortPolicy implements RejectedExecutionHandler {
public AbortPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
//丢弃任务,但是不抛出异常。
public static class DiscardPolicy implements RejectedExecutionHandler {
public DiscardPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
//丢弃队列最前面的任务,然后重新提交被拒绝的任务
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
public DiscardOldestPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
CPU密集型和IO密集型
了解:IO密集型,CPU密集型:(调优)
池的最大的大小如何去设置! 最大线程该如何定义?
- CPU 密集型,几核,就是几,可以保持CPU的效率最高!线程数等于cpu数是最好的了!
package demo7;
import java.util.concurrent.*;
/**
* 手动创建线程池
* <p>
* int corePoolSize,
* int maximumPoolSize,
* long keepAliveTime,
* TimeUnit unit,
* BlockingQueue<Runnable> workQueue,
* ThreadFactory threadFactory,
* RejectedExecutionHandler handler
*/
public class ExecutorsTest2 {
public static void main(String[] args) {
//获取cpu的核数
System.out.println(Runtime.getRuntime().availableProcessors());
//自定义线程池
ExecutorService executorService = new ThreadPoolExecutor(
2,
Runtime.getRuntime().availableProcessors(),//获取cpu核数
3,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy() //默认 银行满了,还有人进来,不处理这个人,抛出异常
// new ThreadPoolExecutor.DiscardOldestPolicy()//队列满了, 丢掉任务 ,不会抛出异常
// new ThreadPoolExecutor.CallerRunsPolicy()//哪来的哪去
// new ThreadPoolExecutor.DiscardOldestPolicy()//队列满了,尝试和最早的竞争,不会抛出异常
);
try {
//最大承载 = 队列 deque + max
//超出抛出RejectedExecutionException 异常
for (int i = 1; i <= 10; i++) {
executorService.execute(() -> {
System.out.println(Thread.currentThread().getName() + "=>ok");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭线程池
executorService.shutdown();
}
}
}
- IO 密集型 > 判断你程序中十分耗IO的线程, 假如 程序有 15个大型任务, io十分占用资源!可以设置线程为30,大约两倍。