精华内容
下载资源
问答
  • ⑤以后提供的线程池 为我们提供了很好的线程的管理能够帮助我们管理线程的生命周期 初始化 等待 和销毁因为无限制的开启线程是需要销毁CPU和内存的 容易造成内存溢出 或服务崩溃了解各种线程池适应各种业务场景当然 ...

    望大神们赐教:

    ①.实际工作中的使用

    ②.进阶技术的使用

    后台本身大致可以分为同步和异步两种情况

    异步情况①定会考虑使用线程的场景

    而JDK①.⑤以后提供的线程池 为我们提供了很好的线程的管理

    能够帮助我们管理线程的生命周期 初始化 等待 和销毁

    因为无限制的开启线程是需要销毁CPU和内存的 容易造成内存溢出 或服务崩溃

    了解各种线程池适应各种业务场景

    当然 深入理解的话 可以学习自定义线程池 那就是更底层的封装了 可以根据自己项目的业务场景定义

    总之为什么要学习 就是在异步场景下 尝试最大合理化利用服务器资源

    比如你开发服务器,既要充分利用服务器多CPU、多核等特性,又要避免频繁创建、销毁线程带来的开销,这个时候就要用线程池。

    比如你做下载类的软件,像迅雷,也会用线程池,道理是类似的。

    还有像视频编解码、转码之类的软件,很多都会用到线程池。

    我是搬运工,以下答案均来自于并发编程网(如何合理地估算线程池大小?)。我只是部分整理了①下。

    ①般说来,大家认为线程池的大小经验值应该这样设置:(其中N为CPU的个数)

    如果是CPU密集型应用,则线程池大小设置为N+①如果是IO密集型应用,则线程池大小设置为②N+①如果①台服务器上只部署这①个应用并且只有这①个线程池,那么这种估算或许合理,具体还需自行测试验证。

    但是,IO优化中,这样的估算公式可能更适合:

    最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU数目

    因为很显然,线程等待时间所占比例越高,需要越多线程。线程CPU时间所占比例越高,需要越少线程。

    下面举个例子:

    比如平均每个线程CPU运行时间为⓪.⑤s,而线程等待时间(非CPU运行时间,比如IO)为①.⑤s,CPU核心数为⑧ · 那么根据上面这个公式估算得到:((⓪.⑤+①.⑤)/⓪.⑤)*⑧=③②。这个公式进①步转化为:

    最佳线程数目 = (线程等待时间与线程CPU时间之比 + ①)* CPU数目

    刚刚说到的线程池大小的经验值,其实是这种公式的①种估算值。

    编后语:关于《学习线程池有什么样用?java线程池大小为何会大多被设置成CPU核心数+1》关于知识就介绍到这里,希望本站内容能让您有所收获,如有疑问可跟帖留言,值班小编第一时间回复。

    下一篇内容是有关《android可以通过进入程序后台关闭运行程序达到减少内存占用的目的?a6处理器相当于安卓手机的什么样处理器》,感兴趣的同学可以点击进去看看。

    资源转载网络,如有侵权联系删除。

    展开全文
  • java 线程池存在意义很多刚接接触线程池的人会很纳闷,我明明可以new Thread().start() 启动我想要的线程,那么为什么还多此一举,用线程池呢?首先要明白程序最重要运行到一台机器上的,那么对于一台机器来说, 他...

    java 线程池存在意义

    很多刚接接触线程池的人会很纳闷,我明明可以用new Thread().start() 启动我想要的线程,那么为什么还多此一举,用线程池呢?

    首先要明白程序最重要运行到一台机器上的,那么对于一台机器来说, 他的CPU,IO,网络,DB等资源是有限的,因此我们用的时候不能够随意支取,而是要有一个中介来统一接收请求,然后中介去帮忙对资源进行控制,调度,回收(数据库连接池也是一个道理,为了防止程序频繁无休止的创建Connection把数据库拖挂,所以用了连接池)。

    线程对于一台机器来说是稀缺资源, 因此程序里面不能随意的new Thread,而应该通过创建一个全局Globa的 Thread Pool,然后大家如果想要申请使用Thread资源的话,统一给线程池下发任务,然后线程池里面有一个Task Queue缓存任务,然后线程池根据配置,结合当前机器的运行状况,开线程从Task QUeue中消费Task运行,这样防止把机器的线程资源耗尽

    线程的生老病死都是要耗费性能的,所以最好不要频繁的创建回收Thread,浪费机器性能。因此用一个线程池,一直开着一定数量的线程,当有Task来了,就取线程消费Task Queue

    解耦, 调用方只用创建Task,然后传给线程池,线程池缓存Task,然后线程池中的Thread消费Task Queue,这样达到Task创建和执行的解耦。

    java如何创建线程池

    比较常用的 用Executors的各种静态方法创建需要的线程池

    ExecutorService cachedthreadPool = Executors.newCachedThreadPool();

    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(1);

    ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1);

    ExecutorService SingleThreadPool = Executors.newSingleThreadExecutor();

    其实Executors的四种方法底层都是用 new ThreadPoolExecutor 来创建线程池的,因此为了搞清楚上面四种方法的区别,我们还是深入研究一下ThreadPoolExecutor的原理,为了研究ThreadPoolExector的原理我们先画图讲解JAVA 线程池的原理

    Executors.newCachedThreadPool()

    public static ExecutorService newCachedThreadPool() {

    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,

    60L, TimeUnit.SECONDS,

    new SynchronousQueue());

    }

    可以看到: newCachedThreadPool结果会创建一个最小0 -- Integer.MAX_VALUE个线程, 使用SynchronousQueue接受Task,如果队列满了,等待 60S,如果等待超时那么调用默认的defaultHandler也就是new AbortPolicy()

    Executors.newFixedThreadPool()

    /**

    * Creates a thread pool that reuses a fixed number of threads

    * operating off a shared unbounded queue. At any point, at most

    * nThreads threads will be active processing tasks.

    * If additional tasks are submitted when all threads are active,

    * they will wait in the queue until a thread is available.

    * If any thread terminates due to a failure during execution

    * prior to shutdown, a new one will take its place if needed to

    * execute subsequent tasks. The threads in the pool will exist

    * until it is explicitly {@link ExecutorService#shutdown shutdown}.

    *

    * @param nThreads the number of threads in the pool

    * @return the newly created thread pool

    * @throws IllegalArgumentException if {@code nThreads <= 0}

    */

    public static ExecutorService newFixedThreadPool(int nThreads) {

    return new ThreadPoolExecutor(nThreads, nThreads,

    0L, TimeUnit.MILLISECONDS,

    new LinkedBlockingQueue());

    }

    可以看到: newFixedThreadPool 结果会创建一个最小0 -- nThreads个线程, 使用 LinkedBlockingQueue 接受Task,如果队列满了,不等待,直接调用默认的defaultHandler也就是new AbortPolicy()

    Executors.newScheduledThreadPool()

    public static ScheduledExecutorService newSingleThreadScheduledExecutor() {

    return new DelegatedScheduledExecutorService

    (new ScheduledThreadPoolExecutor(1));

    }

    其中的 ScheduledThreadPoolExecutor 如下

    /**

    * Creates a new {@code ScheduledThreadPoolExecutor} with the

    * given core pool size.

    *

    * @param corePoolSize the number of threads to keep in the pool, even

    * if they are idle, unless {@code allowCoreThreadTimeOut} is set

    * @throws IllegalArgumentException if {@code corePoolSize < 0}

    */

    public ScheduledThreadPoolExecutor(int corePoolSize){

    super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,

    new DelayedWorkQueue());

    }

    比较推荐的创建线程池方法是

    因为Executors底层还是调用new ThreadPoolExecutor创建线程池,因此在平时使用的时候还是比较推荐直接使用ThreadPoolExecutor创建

    java 线程池原理和处理流程

    如果所示

    threadPool.png

    创建线程池 ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, Executors.defaultThreadFactory(), new ArrayBlockingQueue(5), rejectedExecutionHandler)

    【调用方提交Task】 调用 threadPoolExecutor.execute(task)或者threadPoolExecutor.submit(task)给线程池提交task

    【threadPoolExecutor把task防区WorkQueue队列中】,等待线程池中Thread消费Task

    【判断coreThreadPool线程额数是否达到最大】如果没有,且WorkQueue有堆积的Task那么,多开线程消费Task

    【如果线程已经达到最大值,且WorkQueue已经满了,且又有新的Task来了,那么触发饱和策略】rejectedExecutionHandler

    常见的饱和策略: 1) 直接丢弃; 2)调用发自己写rejectedExecutionHandler处理这些Task; 3)丢弃队列中的最近任务

    合理配置线程池内core thread个数

    线程池中的线程个数不是越大越好,要根据任务分类来的。

    IO密集型任务: 线程个数增大,可以增加系统的吞吐。比如可以配置线程个数为 CPU线程数的2倍

    计算密集型任务: 为了避免频繁切换CPU线程上下文,所以线程个数应该跟根据CPU核数配置,CPU线程数的0.8倍。比如CPU是2核4线程的,那么计算密集型的话,可以配置线程最大个数为 4 * 0.8 = 3个

    混合型任务: 可以结合上面两类综合考虑配置

    一些外面文章说的不恰当的论述

    1. 线程池不用的时候为什么要调用shutDown() ?

    网上一贯回答: 我们是为了不让线程池再新加task。

    个人理解

    为了解答这个问题,直接看源码最直接,省的弯弯绕绕的。

    public void shutdown(){

    final ReentrantLock mainLock = this.mainLock;

    mainLock.lock();

    try {

    checkShutdownAccess();

    advanceRunState(SHUTDOWN);

    interruptIdleWorkers();

    onShutdown(); // hook for ScheduledThreadPoolExecutor

    } finally {

    mainLock.unlock();

    }

    //核心地方在这里

    tryTerminate();

    }//这个会一直轮训, 直到所有task执行完,然后销毁线程池的线程,关闭线程池

    final void tryTerminate() {

    for (;;) {

    int c = ctl.get();

    if (isRunning(c) ||

    runStateAtLeast(c, TIDYING) ||

    (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))

    return;

    if (workerCountOf(c) != 0) { // Eligible to terminate

    interruptIdleWorkers(ONLY_ONE);

    return;

    }

    final ReentrantLock mainLock = this.mainLock;

    mainLock.lock();

    try {

    if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {

    try {

    terminated();

    } finally {

    ctl.set(ctlOf(TERMINATED, 0));

    termination.signalAll();

    }

    return;

    }

    } finally {

    mainLock.unlock();

    }

    // else retry on failed CAS

    }

    }

    综上:

    主要目的是当线程池不用的时候, 销毁线程池维持的线程,关闭线程池

    展开全文
  • java 线程池存在意义很多刚接接触线程池的人会很纳闷,我明明可以new Thread().start() 启动我想要的线程,那么为什么还多此一举,用线程池呢?首先要明白程序最重要运行到一台机器上的,那么对于一台机器来说, 他...

    java 线程池存在意义

    很多刚接接触线程池的人会很纳闷,我明明可以用new Thread().start() 启动我想要的线程,那么为什么还多此一举,用线程池呢?

    首先要明白程序最重要运行到一台机器上的,那么对于一台机器来说, 他的CPU,IO,网络,DB等资源是有限的,因此我们用的时候不能够随意支取,而是要有一个中介来统一接收请求,然后中介去帮忙对资源进行控制,调度,回收(数据库连接池也是一个道理,为了防止程序频繁无休止的创建Connection把数据库拖挂,所以用了连接池)。

    线程对于一台机器来说是稀缺资源, 因此程序里面不能随意的new Thread,而应该通过创建一个全局Globa的 Thread Pool,然后大家如果想要申请使用Thread资源的话,统一给线程池下发任务,然后线程池里面有一个Task Queue缓存任务,然后线程池根据配置,结合当前机器的运行状况,开线程从Task QUeue中消费Task运行,这样防止把机器的线程资源耗尽

    线程的生老病死都是要耗费性能的,所以最好不要频繁的创建回收Thread,浪费机器性能。因此用一个线程池,一直开着一定数量的线程,当有Task来了,就取线程消费Task Queue

    解耦, 调用方只用创建Task,然后传给线程池,线程池缓存Task,然后线程池中的Thread消费Task Queue,这样达到Task创建和执行的解耦。

    java如何创建线程池

    比较常用的 用Executors的各种静态方法创建需要的线程池

    ExecutorService cachedthreadPool = Executors.newCachedThreadPool();

    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(1);

    ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1);

    ExecutorService SingleThreadPool = Executors.newSingleThreadExecutor();

    其实Executors的四种方法底层都是用 new ThreadPoolExecutor 来创建线程池的,因此为了搞清楚上面四种方法的区别,我们还是深入研究一下ThreadPoolExecutor的原理,为了研究ThreadPoolExector的原理我们先画图讲解JAVA 线程池的原理

    Executors.newCachedThreadPool()

    public static ExecutorService newCachedThreadPool() {

    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,

    60L, TimeUnit.SECONDS,

    new SynchronousQueue());

    }

    可以看到: newCachedThreadPool结果会创建一个最小0 -- Integer.MAX_VALUE个线程, 使用SynchronousQueue接受Task,如果队列满了,等待 60S,如果等待超时那么调用默认的defaultHandler也就是new AbortPolicy()

    Executors.newFixedThreadPool()

    /**

    * Creates a thread pool that reuses a fixed number of threads

    * operating off a shared unbounded queue. At any point, at most

    * nThreads threads will be active processing tasks.

    * If additional tasks are submitted when all threads are active,

    * they will wait in the queue until a thread is available.

    * If any thread terminates due to a failure during execution

    * prior to shutdown, a new one will take its place if needed to

    * execute subsequent tasks. The threads in the pool will exist

    * until it is explicitly {@link ExecutorService#shutdown shutdown}.

    *

    * @param nThreads the number of threads in the pool

    * @return the newly created thread pool

    * @throws IllegalArgumentException if {@code nThreads <= 0}

    */

    public static ExecutorService newFixedThreadPool(int nThreads) {

    return new ThreadPoolExecutor(nThreads, nThreads,

    0L, TimeUnit.MILLISECONDS,

    new LinkedBlockingQueue());

    }

    可以看到: newFixedThreadPool 结果会创建一个最小0 -- nThreads个线程, 使用 LinkedBlockingQueue 接受Task,如果队列满了,不等待,直接调用默认的defaultHandler也就是new AbortPolicy()

    Executors.newScheduledThreadPool()

    public static ScheduledExecutorService newSingleThreadScheduledExecutor() {

    return new DelegatedScheduledExecutorService

    (new ScheduledThreadPoolExecutor(1));

    }

    其中的 ScheduledThreadPoolExecutor 如下

    /**

    * Creates a new {@code ScheduledThreadPoolExecutor} with the

    * given core pool size.

    *

    * @param corePoolSize the number of threads to keep in the pool, even

    * if they are idle, unless {@code allowCoreThreadTimeOut} is set

    * @throws IllegalArgumentException if {@code corePoolSize < 0}

    */

    public ScheduledThreadPoolExecutor(int corePoolSize){

    super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,

    new DelayedWorkQueue());

    }

    比较推荐的创建线程池方法是

    因为Executors底层还是调用new ThreadPoolExecutor创建线程池,因此在平时使用的时候还是比较推荐直接使用ThreadPoolExecutor创建

    java 线程池原理和处理流程

    如果所示

    threadPool.png

    创建线程池 ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, Executors.defaultThreadFactory(), new ArrayBlockingQueue(5), rejectedExecutionHandler)

    【调用方提交Task】 调用 threadPoolExecutor.execute(task)或者threadPoolExecutor.submit(task)给线程池提交task

    【threadPoolExecutor把task防区WorkQueue队列中】,等待线程池中Thread消费Task

    【判断coreThreadPool线程额数是否达到最大】如果没有,且WorkQueue有堆积的Task那么,多开线程消费Task

    【如果线程已经达到最大值,且WorkQueue已经满了,且又有新的Task来了,那么触发饱和策略】rejectedExecutionHandler

    常见的饱和策略: 1) 直接丢弃; 2)调用发自己写rejectedExecutionHandler处理这些Task; 3)丢弃队列中的最近任务

    合理配置线程池内core thread个数

    线程池中的线程个数不是越大越好,要根据任务分类来的。

    IO密集型任务: 线程个数增大,可以增加系统的吞吐。比如可以配置线程个数为 CPU线程数的2倍

    计算密集型任务: 为了避免频繁切换CPU线程上下文,所以线程个数应该跟根据CPU核数配置,CPU线程数的0.8倍。比如CPU是2核4线程的,那么计算密集型的话,可以配置线程最大个数为 4 * 0.8 = 3个

    混合型任务: 可以结合上面两类综合考虑配置

    一些外面文章说的不恰当的论述

    1. 线程池不用的时候为什么要调用shutDown() ?

    网上一贯回答: 我们是为了不让线程池再新加task。

    个人理解

    为了解答这个问题,直接看源码最直接,省的弯弯绕绕的。

    public void shutdown(){

    final ReentrantLock mainLock = this.mainLock;

    mainLock.lock();

    try {

    checkShutdownAccess();

    advanceRunState(SHUTDOWN);

    interruptIdleWorkers();

    onShutdown(); // hook for ScheduledThreadPoolExecutor

    } finally {

    mainLock.unlock();

    }

    //核心地方在这里

    tryTerminate();

    }//这个会一直轮训, 直到所有task执行完,然后销毁线程池的线程,关闭线程池

    final void tryTerminate() {

    for (;;) {

    int c = ctl.get();

    if (isRunning(c) ||

    runStateAtLeast(c, TIDYING) ||

    (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))

    return;

    if (workerCountOf(c) != 0) { // Eligible to terminate

    interruptIdleWorkers(ONLY_ONE);

    return;

    }

    final ReentrantLock mainLock = this.mainLock;

    mainLock.lock();

    try {

    if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {

    try {

    terminated();

    } finally {

    ctl.set(ctlOf(TERMINATED, 0));

    termination.signalAll();

    }

    return;

    }

    } finally {

    mainLock.unlock();

    }

    // else retry on failed CAS

    }

    }

    综上:

    主要目的是当线程池不用的时候, 销毁线程池维持的线程,关闭线程池

    展开全文
  • JAVA线程池解析什么是线程池线程池带来的好处线程池可选择的阻塞队列基于数组的界阻塞队列基于链表的界/无界阻塞队列同步移交阻塞队列 什么是线程池 线程池顾名思义就是事先创建若干个可执行的线程放入一个池...

    什么是线程池

    线程池顾名思义就是事先创建若干个可执行的线程放入一个池(容器)中,需要的时候就从池中获取线程不用自行创建,使用完毕不需要销毁线程而是放回池中,从而减少创建和销毁线程对象的开销

    线程池带来的好处

    1. 降低资源消耗
    2. 提高相应速度
    3. 提高线程的可管理性

    线程池可选择的阻塞队列

    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.LinkedBlockingQueue;
    import java.util.concurrent.SynchronousQueue;
    

    基于数组的有界阻塞队列

     @Test
        public void arrayBlockingQueue() throws InterruptedException {
            /**
             * 基于数组的有界阻塞队列,队列容量为10
             */
            ArrayBlockingQueue queue =
                    new ArrayBlockingQueue<Integer>(10);
    
            // 循环向队列添加元素
            for (int i = 0; i < 20; i++) {
                queue.put(i);
                System.out.println("向队列中添加值:" + i);
            }
        }
    

    基于链表的有界/无界阻塞队列

        @Test
        public void linkedBlockingQueue() throws InterruptedException {
            /**
             * 基于链表的有界/无界阻塞队列,队列容量为10
             */
            LinkedBlockingQueue queue =
                    new LinkedBlockingQueue<Integer>();
    
            // 循环向队列添加元素
            for (int i = 0; i < 20; i++) {
                queue.put(i);
                System.out.println("向队列中添加值:" + i);
            }
        }
    

    同步移交阻塞队列

    (直接提交) 如果不希望任务在队列中等待而是希望将任务直接移交给工作线程,可使用SynchronousQueue作为等待队列。SynchronousQueue不是一个真正的队列,而是一种线程之间移交的机制。要将一个元素放入SynchronousQueue中,必须有另一个线程正在等待接收这个元素。只有在使用无界线程池或者有饱和策略时才建议使用该队列。

    工作队列的默认选项是 SynchronousQueue,此策略可以 避免在处理可能具有内部依赖性的请求集时出现锁。

    该Queue本身的特性,在某次添加元素后必须等待其他线程取走后才能继续添加。

    @Test
        public void test() throws InterruptedException {
            /**
             * 同步移交阻塞队列
             */
            SynchronousQueue queue = new SynchronousQueue<Integer>();
    
            // 插入值
            new Thread(() -> {
                try {
                    queue.put(1);
                    System.out.println("插入成功");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
    
            // 删除值
    
            new Thread(() -> {
                try {
                    queue.take();
                    System.out.println("删除成功");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
    
    
            Thread.sleep(1000L * 60);
        }
    

    线程池可选择的饱和策略

    • AbortPolicy终止策略(默认)
    • DiscardPolicy抛弃策略
    • DiscardOldestPolicy抛弃旧任务策略
    • CallerRunsPolicy调用者运行策略

    线程池的执行示意图

    在这里插入图片描述

    1. 主线程执行execute,将任务提交到核心线程池,核心线程池进行处理或新增核心线程
    2. 如果核心线程池满了,则会将任务提交到阻塞队列里面,核心线程会轮询消费阻塞队列
    3. 阻塞队列也满了则会将任务提交到最大线程池里面,让非核心线程处理
    4. 非核心线程也增加到了最大线程池,则会引起饱和策略

    在这里插入图片描述

    常用的线程池

    常用的线程池之newCachedThreadPool

    /**
         * 线程数量无限的线程池(核心线程为0,最大线程数是无限大的值,默认的阻塞队列是同步移交策略,意味着有一个任务就有有一个线程去消费,然后去接受另一个任务,这个线程池会创建无数个线程最终系统崩溃)
         *
         * @return
         */
         
    public static ExecutorService newCachedThreadPool() {
            return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
        }
    

    常用的线程池之newFixedThreadPool

        /**
         * 线程数量固定线程池(线程个数虽然固定了,但是无界的队列是没有限制的,任务队列也是会把内存挤爆的)
         * @param nThreads
         * @return
         */
         
        public static ExecutorService newFixedThreadPool(int nThreads) {
            return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
        }
    

    常用的线程池之newSingleThreadExecutor

        /**
         * 单一线程池
         */
        public static ExecutorService newSingleThreadExecutor() {
            return new Executors.FinalizableDelegatedExecutorService
                    (new ThreadPoolExecutor(1, 1,
                            0L, TimeUnit.MILLISECONDS,
                            new LinkedBlockingQueue<Runnable>()));
        }
    

    向线程池提交任务

    import org.junit.Test;
    
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    public class RunTest {
    
        @Test
        public void submitTest()
                throws ExecutionException, InterruptedException {
    
            // 创建线程池
            ExecutorService threadPool =
                    Executors.newCachedThreadPool();
    
            /**
             * 利用submit方法提交任务,接收任务的返回结果
             */
            Future<Integer> future = threadPool.submit(() -> {
                Thread.sleep(1000L * 10);
    
                return 2 * 5;
            });
    
            /**
             * 阻塞方法,直到任务有返回值后,才向下执行
             */
            Integer num = future.get();
    
            System.out.println("执行结果:" + num);
        }
    
        @Test
        public void executeTest() throws InterruptedException {
            // 创建线程池
            ExecutorService threadPool =
                    Executors.newCachedThreadPool();
    
            /**
             * 利用execute方法提交任务,没有返回结果
             */
            threadPool.execute(() -> {
                try {
                    Thread.sleep(1000L * 10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
                Integer num = 2 * 5;
                System.out.println("执行结果:" + num);
            });
    
    
    
            Thread.sleep(1000L * 1000);
        }
    
    }
    
    

    线程池的状态

    在这里插入图片描述

    线程池饱的四种饱和策略使用与代码调试

    定义线程池

    /**
         * 线程池
         */
        private static ThreadPoolExecutor executor =
                new ThreadPoolExecutor(
                        // 核心线程数和最大线程数
                        2, 3,
    
                        // 线程空闲后的存活时间
                        60L, TimeUnit.SECONDS,
    
                        // 有界阻塞队列
                        new LinkedBlockingQueue<Runnable>(5)
               );
    

    重写线程执行

        /**
         * 任务
         */
        class Task implements Runnable {
            /**
             * 任务名称
             */
            private String taskName;
    
            public Task(String taskName) {
                this.taskName = taskName;
            }
    
            @Override
            public void run() {
                System.out.println("线程[ " + Thread.currentThread().getName()
                        + " ]正在执行[ " + this.taskName + " ]任务...");
    
                try {
                    Thread.sleep(1000L * 5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
                System.out.println("线程[ " + Thread.currentThread().getName()
                        + " ]已执行完[ " + this.taskName + " ]任务!!!");
            }
        }
        
    

    终止策略

    demo

        /**
         * 终止策略
         * TODO 抛出异常,拒绝任务提交
         */
        @Test
        public void abortPolicyTest() {
            // 设置饱和策略为 终止策略
            executor.setRejectedExecutionHandler(
                    new ThreadPoolExecutor.AbortPolicy());
    
            for (int i = 1; i <= 10; i++) {
                try {
                    // 提交10个线程任务
                    executor.execute(new Task("线程任务" + i));
                } catch (Exception e) {
                    System.err.println(e);
                }
            }
    
            // 关闭线程池
            executor.shutdown();
        }
        
    

    执行结果

    在这里插入图片描述

    结果说明(线程池的执行过程)

    1. 2个任务进入核心线程
    2. 第3个到第7个任务,会暂存到任务队列中,因为有界队列定义为5
    3. 第8个任务,会启动最大线程,去执行
    4. 第9个第10任务,没有线程可以去执行,被终止抛出

    抛弃策略

    demo

       /**
        * 抛弃策略
        * TODO 直接丢弃掉新提交的任务
        */
       @Test
       public void discardPolicyTest() {
           // 设置饱和策略为 抛弃策略
           executor.setRejectedExecutionHandler(
                   new ThreadPoolExecutor.DiscardPolicy());
    
           for (int i = 1; i <= 10; i++) {
               try {
                   // 提交10个线程任务
                   executor.execute(new Task("线程任务" + i));
               } catch (Exception e) {
                   System.err.println(e);
               }
           }
    
           // 关闭线程池
           executor.shutdown();
       }
    

    执行结果

    在这里插入图片描述

    结果说明

    线程任务第9与第10因为已满则被直接抛弃

    抛弃旧任务策略

    demo

       /**
        * 抛弃旧任务策略
        * TODO 丢弃掉任务队列中的旧任务,暂存新提交的任务
        */
       @Test
       public void discardOldestPolicyTest() {
           // 设置饱和策略为 抛弃旧任务策略
           executor.setRejectedExecutionHandler(
                   new ThreadPoolExecutor.DiscardOldestPolicy());
    
           for (int i = 1; i <= 10; i++) {
               try {
                   // 提交10个线程任务
                   executor.execute(new Task("线程任务" + i));
               } catch (Exception e) {
                   System.err.println(e);
               }
           }
    
           // 关闭线程池
           executor.shutdown();
       }
    

    执行结果

    在这里插入图片描述

    结果说明

    线程3与线程4进入优先进入队列等待,也是最先被抛弃

    调用者运行策略

    demo

       /**
        * 调用者运行策略
        * TODO 借用主线程来执行多余任务
        */
       @Test
       public void callerRunsPolicyTest() {
           // 设置饱和策略为 调用者运行策略
           executor.setRejectedExecutionHandler(
                   new ThreadPoolExecutor.CallerRunsPolicy());
    
           for (int i = 1; i <= 10; i++) {
               try {
                   // 提交10个线程任务
                   executor.execute(new Task("线程任务" + i));
               } catch (Exception e) {
                   System.err.println(e);
               }
           }
    
           // 关闭线程池
           executor.shutdown();
       }
    

    执行结果

    在这里插入图片描述

    结果说明

    线程任务9与10因为满了,则让主程执行,这就是调用者运行策略

    展开全文
  • 详解Java线程池和Executor原理的分析线程池作用与基本知识在开始之前,我们先来讨论下...或者说与直接Thread相比,有什么优势?我简单总结了以下几点:减小线程创建和销毁带来的消耗对于Java Thread的实现,...
  • 什么需要线程池? 如果没有线程池,我们平常所创建的线程在运行结束后都会被虚拟机销毁,如果任务数量多的话,频繁的创建和销毁线程会浪费大量时间,降低任务效率,创建过多的线程也会使内存开销吃紧。 线程池是一...
  • 刚刚研究了一下线程池,如果不足之处,请大家不吝赐教,大家共同学习、共同交流。...线程池工作原理:为什么用线程池?诸如 Web 服务器、数据库服务器、文件服务器或邮件服务器之类的许多服...
  • java线程池

    2020-11-18 23:37:32
    线程池什么线程池什么要使用线程池可以在哪些地方使用线程池的好处举几个例子 什么线程池 线程池就是创建若干个可执行的线程放入一个池(容器)中,任务需要处理时,会提交到线程池中的任务队列,处理完...
  • Java线程池

    2017-10-21 16:22:32
    1、Java线程池是一个放线程的池子,指的就是里面很多个线程,池子怎么实现呢,用什么东西来表示,考虑到数据结构吗,跟连接池类似吗。 2、里面的线程是用来干什么的。 3、线程池中的线程是在什么时候创建的,...
  • JAVA线程池

    2021-03-23 16:29:05
    事先准备好一些资源,人要就来我这取,用来之后还回来给我,类似于共享充电宝。 什么是池化技术 程序的运行本质是系统资源的占用,池化就是为了优化资源的使用,提高响应速度。 线程池的优点 降低系统资源的消耗...
  • Java 线程池

    2020-05-21 15:22:12
    Java 四种线程池的使用 1,线程池的作用 线程池作用就是限制系统中执行线程的数量。 根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳...2,为什么用线程池? 1.减少了创建和销毁线程的次数,每个工
  • java 线程池

    2020-06-30 22:49:46
    什么用线程池(自己的理解, 如错误,评论区指导~)  以web服务器为例, 其实在低并发量的时候,我觉的不使用线程池也没有太大关系。但是一旦并发量上来了,或者人对你的网站发起恶意流量攻击, 那么假如我们...
  • JAVA线程池解析

    2020-08-17 11:17:42
    JAVA线程池什么线程池 概念 我们在数据库连接池中也接触过,那线程池顾名思义就是存放线程的池子,是一个容器,我们预先创建若干线程放在容器中,使用的时候直接拿来完放回去。 优势 线程的创建与销毁...
  • java有线程池、连接池等等。线程池就是在系统启动或者实例化池时创建一些空闲的线程,等待工作调度,执行完任务后,线程并不会立即被销毁,而是重新处于空闲状态,等待下一次调度。线程池的工作机制?在线程池的...
  • newSingleThreadExecutor public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 794
精华内容 317
关键字:

java线程池有什么用

java 订阅