目录
RejectedExecutionHandler handler
1.ThreadPoolExecutor.Abortpolicy
2.ThreadPoolExecutor.CallerRunsPolicy
3.ThreadPoolExecutor.DiscardOldestPolicy
4.ThreadPoolExecutor.DiscardPolicy
概念:
了解线程池,首先我们要了解池的概念
池:把要用的对象准备好,用完的对象不要释放,而是留着下次使用.例如常量池,数据库连接池,线程池进程池,内存池.
我们计算机引入线程是线程的创建和销毁开销少,可以减少计算机的负担,但是大量线程进行创建和销毁还是会使电脑的处理效率下降
所以我们引出了线程池的概念
所谓线程池,就是我们提前创建好多个线程,使用完成之后不销毁已备下次使用
ThreadPoolExecutor
标准库的线程池 ThreadPoolExecutor 其构造方法参数十分重要.
int corePoolSize
核心线程数量,最少有多少个线程. (相当于一个公司的正式员工)
int maximumPoolsize
最大线程数量,最多有多少个线程.(多出来的这些相当于外包员工,召之即来,挥之即去)
long keepAliveTime
最长存活时间.(当外包员工没有任务时,处于空闲状态,等待存活时间后就会将外包员工开除)
TimeUnit unit
时间单位
BlockingQueue<Runnable> wokrQueue
和我们上一期的计时器一样,我们的线程池也是可以执行多个任务的(理所应当的,线程池肯定执行的任务也多),这个优先级队列就是用来储存任务的.
Thread threadFactory
线程工厂
可以设定线程名,守护线程.
RejectedExecutionHandler handler
拒绝策略.在线程池中有阻塞队列,那么容纳的线程就是有极限的.如果线程池已经满了,此时就需要使用拒绝策略.
而我们的拒绝策略有四种:
1.ThreadPoolExecutor.Abortpolicy
继续添加任务直接抛出异常
例如:你现在正在写作业,已经将队列占满了,作业很多,妈妈让你扫地,你作业也不写,地也不扫了,直接什么都不干了.
2.ThreadPoolExecutor.CallerRunsPolicy
新的添加任务由添加任务的线程完成.
妈妈让你扫地,你说你很忙,然后让妈妈去扫地
3.ThreadPoolExecutor.DiscardOldestPolicy
丢弃最早的任务. 不写作业了,只去扫地
4.ThreadPoolExecutor.DiscardPolicy
丢弃最新的任务. 不扫地,只写作业
ExecutorService
Executor相较于ThreadPoolExecutor,都是用来设定线程池,但是很明显,ExecutorService线程池的参数更少,我们在使用中如果只是简单的使用线程池,就可以用这个简化版的.
newFixedThreadPool方法实例化的线程池表示有固定线程数量,括号中就是其线程数量.
而其sumbit很明显是用来提交任务的,但是执行哪个任务的具体线程是随机的.
线程池的简单实现
根据上述线程池的特点,我们可以总结出
1.线程池有多个线程的,所以我们需要一个数据结构来储存线程.
2.任务也是多个,而且我们尽量保证先提交的任务优先进行,此时就需要队列容纳任务
3.构造方法创建n个线程我们需要用循环来创建
4.submit方法接收任务
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue;
class MyExecutorService{
//数组容纳线程
List<Thread> list = new ArrayList<>();
//队列容纳任务
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(10000);
//构造方法
public MyExecutorService(int n ){
for (int i = 0; i < n; i++) {
//构建线程
Thread t = new Thread(() ->{
while(true){
try {
//此处的take是带有阻塞功能的,如果队列为空,take就会进入阻塞
Runnable runnable = queue.take();
runnable.run();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
//启动线程
t.start();
//将线程放入线程数组
list.add(t);
}
}
public void Submit(Runnable runnable){
queue.offer(runnable);
}
}
public class ThreadPool {
public static void main(String[] args) {
MyExecutorService myExecutorService = new MyExecutorService(4);
for (int i = 0; i < 1000; i++) {
int n = i;
//此时每次循环进来都会新建一个n,n不发生改变为事实final变量
myExecutorService.Submit(() ->{
//此处的i涉及到变量捕获,因为i在匿名内部类当中,所以i必须是final或者事实final,事实final就是之后不会改变
//我们可以在循环外部新设置一个变量n,此时n就是事实final,再将i传入final
System.out.println("执行任务"+n+" "+"执行线程"+Thread.currentThread().getName());
});
}
}
}
这个代码总体来说比较简单,没有涉及到大量的线程安全问题.
标签:Thread,int,案例,任务,线程,多线程,final,ThreadPoolExecutor From: https://blog.csdn.net/a13931329858/article/details/136973174