①:减少线程的频繁创建和销毁带来的性能开销,因为线程创建会涉及到 CPU 上下文切换、内存分配等工作。
②:提升快速响应的能力,不需要创建线程,直接在线程池调用就行
③:线程池本身会有参数来控制线程创建的数量,这样就可以避免无休止的创建线程带来的资源利用率过高的问题,起到了资源保护的作用。
④:减少代码之间的耦合,能够实现异步操作(异步:直接发送下一个请求,不需要等待回复)
线程复用技术,因为线程的生命周期时由任务运行的状态决定的,无法人为控制。所以为了实现线程的复用,线程池里面用到了阻塞队列,也就是说线程池里面的工作线程处于一直运行状态,它会从阻塞队列中去获取待执行的任务,一旦队列空了,那这个工作线程就会被阻塞,直到下次有新的任务进来。工作线程是根据任务的情况实现阻塞和唤醒,从而达到线程复用的目的。
最后,线程池里面的资源限制,是通过几个关键参数来控制的,分别是核心线程数、最大线程数。核心线程数表示默认长期存在的工作线程,而最大线程数是根据任务的情况动态创建的线程,主要是提高阻塞队列中任务的处理效率。
线程里面有个死循环
线程池里面存数据的集合是队列

(1)在线程池内部,当我们把一个任务丢给线程池去执行,线程池会调度工作线程来执行这个任务的 run 方法,run 方法正常结束,也就意味着任务完成了。
(线程池中的工作线程是通过同步调用任务的 run()方法并且等待 run 方法返回后,再去统计任务的完成数量。)
(2)如果想在线程池外部去获得线程池内部任务的执行状态,有几种方法可以实现。线程池提供了一个 isTerminated()方法,可以判断线程池的运行状态,我们可以循环判断 isTerminated()方法的返回结果来了解线程池的运行状态,一旦线程池的运行状态是 Terminated,意味着线程池中的所有任务都已经执行完了。想要通过这个方法获取状态的前提是,程序中主动调用了线程池的 shutdown()方法。在实际业务中,一般不会主动去关闭线程池,因此这个方法在实用性和灵活性方面都不是很好。
(3)在线程池中,有一个 submit()方法,它提供了一个 Future 的返回值,我们通过Future.get()方法来获得任务的执行结果,当线程池中的任务没执行完之前future.get()方法会一直阻塞,直到任务执行结束。因此,只要 future.get()方法正常返回,也就意味着传入到线程池中的任务已经执行完成了!
线程池的真正实现类是 ThreadPoolExecutor,其构造方法需要如下参数:
AbortPolicy(默认):丢弃任务,并抛出 RejectedExecutionException 异常。
CallerRunsPolicy:由调用线程处理该任务。
DiscardPolicy:丢弃任务,但是不抛出异常。可以配合这种模式进行自定义的处理方式。
DiscardOldestPolicy:丢弃队列最早的未处理任务,然后重新尝试执行任务。

public class DequeThread {//存储任务private Deque threads=new LinkedList<>();private int defaultThreadCount=4;public DequeThread(){for (int i = 0; i < defaultThreadCount; i++) {Worker worker=new Worker();//当前类实例化的时候,不断在任务列表放任务threads.addLast(worker);//执行任务worker.start();}}private Deque tasks=new LinkedList<>();public int addTask(T task) {synchronized (tasks){//添加的时候也应该锁住tasks.addLast(task);//放任务tasks.notifyAll();//添加新任务时应该做一次唤醒,唤醒全部的来抢任务}return 0;}class Worker extends Thread{@Overridepublic void run() {super.run();while (true){T first=tasks.pollFirst();//取任务synchronized (tasks){//synchronized执行完之后,锁就释放出来了//拿到锁就判断是否为空while(first==null){//防止空指针try {tasks.wait();//为空的时候等待在task上//.wait():让当前线程阻塞在对象上,并把锁释放掉} catch (InterruptedException e) {e.printStackTrace();}//再判断是不是空,如果是空就进下一次循环//应该是取出来再执行first=tasks.pollFirst();}}first.run();//执行任务}}}public static void main(String[] args) {DequeThread thread=new DequeThread<>();thread.addTask(new Thread(new Runnable() {@Overridepublic void run() {System.out.println("1");}}));thread.addTask(new Thread(new Runnable() {@Overridepublic void run() {System.out.println("2");}}));thread.addTask(new Thread(new Runnable() {@Overridepublic void run() {System.out.println("3");}}));}
}
public class DequeThread {//存储任务private Deque threads=new LinkedList<>();private int defaultThreadCount=4;//限制个数,线程安全的计数private AtomicInteger taskCount = new AtomicInteger();private Object full = new Object();public DequeThread(){for (int i = 0; i < defaultThreadCount; i++) {Worker worker=new Worker();//当前类实例化的时候,不断在任务列表放任务threads.addLast(worker);//执行任务worker.start();}}private Deque tasks=new LinkedList<>();public int addTask(T task) throws InterruptedException {synchronized (tasks){//添加的时候也应该锁住synchronized (full){int i = taskCount.incrementAndGet();//自增//如果i加到10,就进行阻塞while (i > 10){full.wait();}}tasks.addLast(task);//放任务//添加新任务时应该做一次唤醒,唤醒全部的来抢任务tasks.notifyAll();}return 0;}class Worker extends Thread{@Overridepublic void run() {super.run();while (true){synchronized (tasks){//synchronized执行完之后,锁就释放出来了//优化——》tasks.pollFirst();放到锁里T first=tasks.pollFirst();//取任务//拿到锁就判断是否为空while(first==null){//防止空指针try {tasks.wait();//为空的时候等待在task上//.wait():让当前线程阻塞在对象上,并把锁释放掉} catch (InterruptedException e) {e.printStackTrace();}//再判断是不是空,如果是空就进下一次循环//应该是取出来再执行first=tasks.pollFirst();}//优化——》first.run();放到锁里first.run();//执行任务//执行完成后,做减一的操作taskCount.decrementAndGet();//阻塞到full上的线程就能被唤醒//如果空间满了,让调用的线程阻塞住synchronized (full){full.notifyAll();}}}}}//main方法里面执行的代码结束了public static void main(String[] args) throws InterruptedException {DequeThread thread=new DequeThread<>();thread.addTask(new Thread(new Runnable() {@Overridepublic void run() {System.out.println("1");}}));thread.addTask(new Thread(new Runnable() {@Overridepublic void run() {System.out.println("2");}}));thread.addTask(new Thread(new Runnable() {@Overridepublic void run() {System.out.println("3");}}));}
}
继承了Thread类,也可以实现Runnable接口,
如何让任务和线程关联起来?
选择了自己封装线程的run方法,让它和提交的任务关联起来;
又因为线程池的线程是优先于任务启动起来的,所以看不到任务,只能借助一个另外的集合private Deque tasks=new LinkedList<>(); tasks这个变量联系起来;
类似于生产者消费者的思想,没有任务的时候等着,有任务的时候执行,进而完成线程池的处理
而且线程池的初始化是在程序运行起来的时候就进行了
所以是线程池运行起来之后,才等着任务进来