多线程--线程池(ThreadPoolExecutor)

线程池是一种管理和复用线程的机制,它能够显著提高多线程程序的性能和稳定性。


线程池的参数介绍

在java的官方文档当中,线程池有四种实现方式,我们选择参数数量最多的一种实现方式进行介绍。

ThreadPoolExecutor(int corePoolsize, int maximumPoolsize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory ,RejectedExecutionHandler handler)

在上述图中我们可以清楚的知道最多有七个参数:int corePoolsize, int maximumPoolsize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory ,RejectedExecutionHandler handler。

  • int corePoolsize:核心线程数,线程池中保持活动状态的最小线程数。
  • int maximumPoolsize:线程池中允许的最大线程数。当工作队列已满且有新任务提交时,线程池会创建新线程,但不会超过这个数量。
  • long keepAliveTime:当线程池中的线程数超过核心线程数时,多余的空闲线程在被终止之前等待新任务的最长时间。
  • TimeUnit unit:时间单位。
  • BlockingQueue<Runnable> workQueue:用于存储待执行任务的阻塞队列。如果当前运行的线程数超过核心线程数,新任务会被放入工作队列中等待执行。
  • ThreadFactory threadFactory:线程工厂,用来定制线程的创建过程。
  • RejectedExecutionHandler handler:拒绝策略,当工作队列已满且线程池中的线程数达到最大线程数时,用于处理新提交的任务的策略。

常见的拒绝策略:

(1)ThreadPoolExecutor.AbortPolicy

A handler for rejected tasks that throws a RejectedExecutionException.

第一种是所有的任务都不做,抛出一个异常,例如:当我们身上有一个任务时,突然接到领导叫我们做一个新任务,这时我们身上的老任务和这个新任务都不做了,直接抛出一个异常。

(2)ThreadPoolExecutor.CallerRunsPolicy

A handler for rejected tasks that runs the rejected task directly in the calling thread of the execute method, unless the executor has been shut down, in which case the task is discarded.

第二种是各自执行自己的任务,还是以上述例子为例,就是我们自身的老任务和新任务都执行,但是我们自身执行我们自己的任务,领导执行他派的任务。

(3)ThreadPoolExecutor.DiscardOldestPolicy

A handler for rejected tasks that discards the oldest unhandled request and then retries execute, unless the executor is shut down, in which case the task is discarded.

第三种是暂停当前任务执行新的任务,以上述例子为例,就是我们把我们自身的老任务先暂停不做了,去完成领导派下来的新任务。

(4)ThreadPoolExecutor.DiscardPolicy

A handler for rejected tasks that silently discards the rejected task.

第四种是新任务不执行执行旧任务,以上述例子为例,就是我们不执行领导派下来的新任务,去执行我们自身的老任务。

以上四种拒绝策略是在线程数达到最大时的处理情况,并且在面试当中常常作为考题! 

线程池的工作流程

  1. 核⼼操作为 submit, 将任务加⼊线程池中。
  2.  使⽤ Runnable 描述⼀个任务。
  3.  使⽤⼀个 BlockingQueue 组织所有的任务。
  4. 每个 worker 线程要做的事情: 不停的从 BlockingQueue 中取任务并执⾏。
  5. 指定⼀下程池中的最⼤线程数 maxWorkerCount; 当当前线程数超过这个最⼤值时, 就不再新增线程了。
package thread;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

class MyThreadPoolExecutoe{

    private BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1000);

    public MyThreadPoolExecutoe(int n){
        for (int i = 0;i < n;i++){
            Thread t = new Thread(()->{
                //
                while (true){
                    try {
                        Runnable runnable = queue.take();
                        runnable.run();
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }
            });
            t.start();
        }
    }

    public void submit(Runnable runnable) throws InterruptedException {
        queue.put(runnable);
    }
}
public class Demo {
    public static void main(String[] args) throws InterruptedException {
        MyThreadPoolExecutoe executor = new MyThreadPoolExecutoe(4);
        for (int i = 0;i <1000;i++){
            int n = i;
            executor.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("执行任务"+ n + " , 当前线程为:"+Thread.currentThread().getName());
                }
            });
        }
    }
}

 

 注意:我们注意到执行任务并不是按照顺序排序的,这是因为线程执行之间的顺序时不确定的,这些线程都是等价的。

使用Executors 创建常见的线程池

  1.  newFixedThreadPool: 创建固定线程数的线程池。
  2. newCachedThreadPool: 创建线程数⽬动态增⻓的线程池。
  3. newSingleThreadExecutor: 创建只包含单个线程的线程池。
  4. newScheduledThreadPool: 设定 延迟时间后执⾏命令,或者定期执⾏命令. 是进阶版的 Timer。

Executors 本质上是 ThreadPoolExecutor 类的封装。

总结

以上便是线程池的介绍,熟练掌握线程池,提高多线程程序的性能和资源利用率。 

  • 15
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值