线程池7大参数,三大方法,四大拒绝策略

Java线程具有五中基本状态

新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();

就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;

运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就     绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;

阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:

1.等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;

2.同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;

3.其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

为什么要使用线程池?

线程池做的工作主要是控制运行的线程的数量,处理过程中将任务放入队列,然后再线程创建后启动这些任务如果线程的数量超过最大数量,超过数量的线程将排队等候,等其他线程执行完毕,再从队列中取出任务来执行

特点:线程复用,控制最大并发数,管理线程

一、降低资源消耗,通过重复利用已创建的线程降低线程创建和销毁造成的消耗

二、提高响应速度,当任务到达时,任务可以不需要的等到线程创建就能够立刻执行

三、提高线程的可管理性,线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,

还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

线程池创建的核心:

   1、七大参数:

  • corePoolSize:线程池核心线程数量,核心线程不会被回收,即使没有任务执行,也会保持空闲状态。如果线程池中的线程少于此数目,则在执行任务时创建。
  • maximumPoolSize:池允许最大的线程数,当线程数量达到corePoolSize,且workQueue队列塞满任务了之后,继续创建线程。
  • keepAliveTime:超过corePoolSize之后的“临时线程”的存活时间。
  • unit:keepAliveTime的单位。
  • workQueue:当前线程数超过corePoolSize时,新的任务会处在等待状态,并存在workQueue中,BlockingQueue是一个先进先出的阻塞式队列实现,底层实现会涉及Java并发的AQS机制,有关于AQS的相关知识,我会单独写一篇,敬请期待。
  • threadFactory:创建线程的工厂类,通常我们会自顶一个threadFactory设置线程的名称,这样我们就可以知道线程是由哪个工厂类创建的,可以快速定位。
  • handler:线程池执行拒绝策略,当线数量达到maximumPoolSize大小,并且workQueue也已经塞满了任务的情况下,线程池会调用handler拒绝策略来处理请求。

    2、四大拒绝策略:

  • AbortPolicy:为线程池默认的拒绝策略,该策略直接抛异常处理。
  • DiscardPolicy:直接抛弃不处理。
  • DiscardOldestPolicy:丢弃队列中最老的任务。
  • CallerRunsPolicy:将任务分配给当前执行execute方法线程来处理。

3、三大方法

           1.Executors.newSingleThreadExecutor();
           2.Executors.newFixedThreadPool(5);
           3.Executors.newCachedThreadPool();

4、线程池最大值如何设置:


      1.CPU密集型
           System.out.println(Runtime.getRuntime().availableProcessors());
           获得cpu的核数,不同的硬件不一样
      2.IO密集型
          大型的程序任务有多少个? IO非常消耗资源
          线程池最大值 > 大型任务的数量即可
          一般设置大型任务的数量*2

//手写线程池
public class MyThreadPoolDemo {
    public static void main(String[] args) {
        System.out.println(Runtime.getRuntime().availableProcessors());

        ExecutorService threadPool = new ThreadPoolExecutor(
                2, //corePoolSize
                5,//maximumPoolSize
                1L,//keepAliveTime
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()
        );

     try
    {
        //模拟10个用户来办理业务,每个用户就是来自外部的请求线程
        for (int i = 1; i <= 10; i++) {

            threadPool.execute(() -> {
                System.out.println(Thread.currentThread().getName() + "\t 办理业务");
            });
        }
    }catch (Exception e){
        e.printStackTrace();
    }finally{
        threadPool.shutdown();
    }
}}


      

线程池拒绝策略是指当线程池已经达到最大工作线程数但仍接收到新的任务时,采取的不同处理方式。常见的几种拒绝策略包括: 1. **AbortPolicy**(默认策略):直接抛出RejectedExecutionException异常,终止当前线程并回滚任务到队列头部。 2. **CallerRunsPolicy**:让调用者(通常主线程)继续运行新任务,而不是放入线程池。这种方式可能导致主线程阻塞,适用于那些不需要并发执行的任务。 3. **DiscardOldestJobPolicy**:丢弃线程池中最早的任务,然后接受新的任务,适用于优先级较高的任务可以随时添加的情况。 4. **DiscardPolicy** 或 **DiscardPolicyFactory**:直接丢弃新任务,不会抛出异常,适合资源有限、任务瞬息万变的场景。 合理分配线程池大小主要考虑以下几个因素: - **CPU核心数**:通常线程数不应超过CPU的核心数,因为过多会增加上下文切换开销。 - **并发任务量**:根据应用预期同时处理的请求量设置。 - **任务性质**:I/O密集型任务可以适当多设,CPU密集型任务应少设避免过度竞争。 - **预留空间**:为了应对突发流量,可以留出一部分空闲线程。 - **吞吐量和响应时间**:需要权衡在保证系统性能的同时,提供足够的快速响应。 要确定具体的线程池大小,可以通过监控系统的负载和调整来优化,或者采用动态调整的算法如Hystrix、Spring ThreadPool等工具。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值