线程池(重点)
1、线程池介绍
线程池:三大方法,7大参数,4种拒绝策略
池化技术
程序的运行,本质:占用系统的资源,优化资源的使用
线程池、连接池、内存池、对象池…创建,销毁。十分浪费资源
池化技术:事先准备好一些资源,有人要用,就来我这里拿,用完之后还给我
线程池的好处:
- 降低资源的消耗
- 提高响应速度
- 方便管理
线程复用、可以控制最大并发数、管理线程
2、线程池:三大方法
public class Dome1 {
public static void main(String[] args) {
// ExecutorService executorService = Executors.newSingleThreadExecutor();//单个线程
// ExecutorService executorService = Executors.newFixedThreadPool(5);//固定线程。都多并发5个线程
ExecutorService executorService = Executors.newCachedThreadPool();//线程个数不固定
try {
for (int i = 0; i < 10; i++) {
//使用了线程池之后,使用线程池来创建线程
executorService.execute(()->{
System.err.println(Thread.currentThread().getName()+"ok");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
executorService.shutdown();//关闭线程池
}
}
}
3、线程池:七大参数
自定义线程池
通过三大方法源码分析可得,底层都是
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
查看ThreadPoolExecutor源码,可以看到7大参数都在这
public ThreadPoolExecutor(int corePoolSize,//线程池大小
int maximumPoolSize,//最大线程池大小
long keepAliveTime,//超时了没有人调用就会释放
TimeUnit unit,//超时单位
BlockingQueue<Runnable> workQueue) {//阻塞队列,也就是等待区
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), //线程工厂
defaultHandler//拒绝策略);
}
自定义线程池
阿里巴巴开发手册规定:
4种拒绝策略
/**
* 4种拒绝策略
* DiscardOldestPolicy:队列满了,尝试了最早的去竞争,也不会抛出异常
* DiscardPolicy:队列满了,丢掉任务,不会抛出异常
* AbortPolicy:队列满了,不处理之后的任务,抛出异常
*
*/
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
//使用最原生的方式创建she
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
2,//线程池大小
5,//最大线程池大小
3,//超时了没有人调用就会释放
TimeUnit.SECONDS,//超时单位
new ArrayBlockingQueue(3),//阻塞队列,也就是等待区
Executors.defaultThreadFactory(),//线程工厂
new ThreadPoolExecutor.CallerRunsPolicy());//拒绝策略
try {
for (int i = 0; i < 9; i++) {
threadPoolExecutor.execute(()->{
System.err.println(Thread.currentThread().getName()+"\tOk");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPoolExecutor.shutdown();
}
}
}
4、CPU密集型和IO密集型
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
/**
* 最大线程如何定义
* CUP密集型 几核,就是几,可以保持CUP的效率最高
* IO密集型 判断程序中十分消耗IO的线程,一般>一倍
*/
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
2,//线程池大小
Runtime.getRuntime().availableProcessors(),//最大线程池大小
3,//超时了没有人调用就会释放
TimeUnit.SECONDS,//超时单位
new ArrayBlockingQueue(3),//阻塞队列,也就是等待区
Executors.defaultThreadFactory(),//线程工厂
new ThreadPoolExecutor.CallerRunsPolicy());//拒绝策略
Runtime.getRuntime().availableProcessors();//获取本机CPU核数
try {
for (int i = 0; i < 9; i++) {
threadPoolExecutor.execute(()->{
System.err.println(Thread.currentThread().getName()+"\tOk");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPoolExecutor.shutdown();
}
}
}
5、死锁的四个条件
一般造成死锁必须同时满足以下4个条件:
- 互斥条件:线程使用的资源必须至少有一个是不能共享的。即在一段时间内,一个资源只能被一个进程占用,直到被该进程释放。
- 请求与保持条件:指的是进程至少有一个资源,但又提出了新的资源请求,而该资源已被其它线程占有,此时请求进程阻塞,但又对自己获得的其它资源保持不释放。
- 不可抢占条件:指的是进程已获得资源,在未使用完之前,不能被抢占,只能在使用完时由自己释放。
- 循环等待条件:第一个线程等待其他的线程释放资源。后者又在等待第一个线程释放资源。
因为要产生死锁,这4个条件必须同时满足。因此要防止死锁的话,只需要破坏其中一个条件即可。