java中的线程池

1)、线程池

(1)、为什么需要使用线程池

        降低资源的消耗,提高线程利用率,降低创建和销毁线程的消耗;

        提高响应速度,任务来了,直接有线程可用可执行,而不是先创建线程,再执行;

        提高线程的可管理性,线程是稀缺资源,使用线程池可以统一分配调优监控;

(2)、线程池的核心参数

public ThreadPoolExecutor(int corePoolSize,//核心线程数,线程池创建好以后就准备就绪的线程数量,就等待来接受异步任务去执行。这些线程创建后并不会消除,而是一种常驻线程。
                              int maximumPoolSize, //最大线程数量,控制资源并发。它与核心线程数相对应,表示最大允许被创建的线程数,比如当前任务较多,将核心线程数都用完了,还无法满足需求时,此时就会创建新的线程,但是线程池内线程总数不会超过最大线程数。
                              long keepAliveTime,//存活时间,表示超出核心线程数之外的线程的空闲存活时间,也就是核心线程不会消除,但是超出核心线程数的部分线程如果空闲一定的时间则会被消除,我们可以通过setKeepAliveTime来设置空闲时间。
                              TimeUnit unit,//时间单位
                              BlockingQueue<Runnable> workQueue,//阻塞队列,如果任务有很多,就会将目前多的任务放在队列里面,只要有线程空闲,就会去队列里面取出新的任务继续执行。假设我们现在核心线程已经被使用,还有任务进来则全部放入队列,直到整个队列被放满但任务还在继续进入则会开始创建新的线程
                              ThreadFactory threadFactory, //线程的创建工厂
                              RejectedExecutionHandler handler //如果队列满了,按照我们指定的策略,拒绝执行任务) 

(3)、线程池的工作流程

        当创建了线程池以后,等待提交过来的任务请求;当调用execute()方法添加一个请求任务时,线程池会做如下判断:

        ①如果正在运行的线程数量小于corePoolSize,那么马上创建线程运行这个任务;

        ②如果正在運行的线程数量大于或等于corePoolSize,那么将这个任务放入队列;

        ③如果这个时候队列满了且正在运行的线程数量还小于maximumPoolSize,那么还是要创建非核心线程立刻执行这个任务;

        ④如果队列满了且正在运行的线程数量大于或等于maximumPoolSize,那么线程池会启动饱和拒绝策略来执行。

        当一个线程完成任务时,它会从队列中取下一个任务来执行;

        当一个线程无事可做超过一定的时间(keepAliveTime),线程池会判断如果当前运行的线程池是否大于corePoolSize,如果大于,那么这个线程就会被停掉。

(4)、线程池的状态

       

        Running,在Running状态下,线程池可以接收新的任务和执行已添加的任务。线程池的初始化状态是Running。换句话是,线程池一旦被创建就处于Running状态,并且线程池中的任务数为0!线程池处在Running状态时,能够接收新任务以及对已添加的任务进行处理。

        shutdown,线程池处在shutdown状态时,不接收新任务,但能处理已添加的任务。当一个线程池调用shutdown()方法时,线程池由running->shutdown。

        stop,线程池处在stop状态时,不接收新任务,不处理已添加的任务,并且会中断正在执行的任务。调用线程池的shutdownNow()方法的时候,线程池由(running或者shutdown)->stop。

        tidying,当所有的任务已终止,记录的任务数量为0,线程池会变为tidying状态。当线程池变为tidying状态时,会执行钩子函数terminated()。terminated()方法在ThreadPoolExecutor类中是空的,没有任何实现。

        terminated,当钩子函数terminated()被执行完成之后,线程池彻底终止,就变成terminated状态。线程池处在tidying状态时,执行完terminated()之后,就会由tidying->terminated。

(5)、线程池中的拒绝策略

        AbortPolicy(默认):直接抛出RejectedException异常阻止系统正常运行

        CallerRunPolicy:调用者运行一种调节机制,该策略既不会抛弃任务,也不会抛出异常

        DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交

        DiscardPolicy:直接丢弃任务,不予任何处理也不抛出异常,如果允许丢失,这是最好的拒绝策略。

(6)、线程池有哪些队列

        ArrayBlockingQueue:基于数组结构的有界阻塞队列,按先进先出对元素进行排序;

        LinkedBlockQueue:基于链表结构的有界/无界阻塞队列,按先进先出对元素进行排序,吞吐量通常高于ArrayBlockQueue,Executors.newFixedThreadPool试用了该队列。

        SynchronousQueue:不是一个真正的队列,而是一种在线程之间移交的机制。要将一个元素放入SynchronousQueue中,必须有另一个线程正在等待接受这个元素。如果没有线程等待,并且线程线程池的当前大小小于最大值,那么线程池将创建一个线程,否则根据拒绝策略,这个任务将被拒绝。使用直接移交将更高效,因为任务会直接移交给执行它的线程,而不是放在队列中,然后由工作线程从队列中提取任务。只有当线程是无界或者可以拒绝任务时,该队列才有实际价值。Executors.newCacahedThreadPool使用了该队列。

        PriorityBlockingQueue:具有优先级的无界队列,按优先级对元素进行排序。元素的优先级是通过自然排序或Comparator来定义的。

(7)、为什么要使用阻塞队列而不是普通队列

        一般的队列只能保证作为一个有限长度的缓冲区,如果超出了缓冲的长度,就无法保留当前的任务了,阻塞队列可以通过阻塞可以保留住当前想要继续入队的任务。

        阻塞队列可以保证任务队列中没有任务时阻塞获取任务的线程,使得线程进入了wait状态,释放了cpu资源。

        阻塞队列自带阻塞和唤醒的功能,不需要额外处理,无任务执行时,线程池李永刚阻塞队列的take方法挂起,从而保持线程的存活、不至于一直占用CPU资源。

(8)、线程池中线程复用的原理

        线程池将线程和任务进行解耦,线程就是线程,任务就是任务,摆脱了之前通过Thread创建线程时的一个线程必须对应一个任务的限制。

        在线程池中,同一个线程可以从阻塞队列中不断获取新任务来执行,其核心原理是在线程池对Thread进行封装,并不是每次执行都会调用Thread.start()来创建线程,而是让每个线程去执行一个循环任务,在这个循坏任务中不停检查是否还有任务需要执行,如果有则执行,也就是调用任务中的run方法,将run方法当一个普通方法执行,通过这种方式只使用固定的线程就将所有任务的run方法串联起来。

(9)、Executors提供了哪些创建线程池的方法

        newFixedThreadPool:固定线程数的线程池。corePoolSize=maximumPoolSize,keepAliveTime=0,工作队列使用无界的LinkedBlockingQueue。适用于为了满足资源管理的需求,而需要限制当前线程数量的场景,适用于负载比较重的服务器。

        newSingleThreadExecutor:只有一个线程的线程池。corePoolSize=maximumPoolSize=1,keepAliveTime为0,工作队列使用无界LinkedBlockingQueue。适用于需要保证顺序的执行各个任务的场景。

        newCachedThreadPool:按需要创建新线程的线程池。核心线程数为0,最大线程数为Integer.MAX_VALUE,keepAliveTime为60秒,工作队列使用同步移交SynchronousQueue。该线程池可以无限扩展,当需求增加时,可以添加新的线程,而当需求降低时会自动回收空闲线程。适用于执行很多的短期异步任务,或者负载较轻的服务器。

        newScheduledThreadPool:创建一个以延迟或定时的方式来执行任务的线程池,工作队列DelayedWorkQueue。适用于需要对个后台线程执行周期任务。

        newWorkStealingPool:jdk1.8新增,用于创建一个可以窃取的线程池,底层使用ForkJoinPool实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java线程池的参数包括以下7个: 1. corePoolSize:线程池的基本大小,即在没有任务需要执行的时候线程池的大小。 2. maximumPoolSize:线程池最大的大小,即线程池允许的最大线程数。 3. keepAliveTime:线程池线程空闲后,保持存活的时间。 4. unit:keepAliveTime的时间单位。 5. workQueue:任务队列,用于保存等待执行的任务的阻塞队列。 6. threadFactory:线程工厂,用于创建新线程。 7. handler:拒绝策略,用于当任务队列已满,且线程池线程数达到maximumPoolSize时,如何拒绝新任务的策略。 下面是一个示例代码,展示了如何使用Java线程池参数: ```java import java.util.concurrent.*; public class ThreadPoolDemo { public static void main(String[] args) { // 创建一个线程池 ThreadPoolExecutor executor = new ThreadPoolExecutor( 2, // corePoolSize 4, // maximumPoolSize 60, // keepAliveTime TimeUnit.SECONDS, // unit new ArrayBlockingQueue<Runnable>(4), // workQueue Executors.defaultThreadFactory(), // threadFactory new ThreadPoolExecutor.AbortPolicy() // handler ); // 提交任务 for (int i = 0; i < 10; i++) { executor.execute(new Task(i)); } // 关闭线程池 executor.shutdown(); } static class Task implements Runnable { private int num; public Task(int num) { this.num = num; } @Override public void run() { System.out.println("正在执行task " + num); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("task " + num + "执行完毕"); } } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值