美文网首页Java
线程池使用场景

线程池使用场景

作者: 芝兰之室也 | 来源:发表于2021-09-09 16:50 被阅读0次

    Java提供四种线程池,分别对应不同的应用场景

    考虑多线程因素:

    任务数、任务执行时间、线程数、CPU核数

    1、newCachedThreadPool

    创建一个线程池,如果线程池中的线程数量过大,它可以有效的回收多余的线程,如果线程数不足,那么它可以创建新的线程。

    • 它是一个可以无限扩大的线程池(corePoolSize为0,maximumPoolSize为无限大意味着线程数量可以无限大);
    • 它比较适合处理执行时间比较小的任务(keepAliveTime为60s,意味着线程空闲时间超过60s就会被杀死);
    • 它采用SynchronousQueue装等待的任务,这个阻塞队列没有存储空间,意味着只要有请求到来,就必须要找到一条工作线程处理他,如果当前没有空闲的线程,那么就会再创建一条新的线程。

    代码示例:

            ExecutorService cachePool = Executors.newCachedThreadPool();
            for(int i=0;i<5;i++){
                cachePool.execute(() -> {
                    System.out.println(Thread.currentThread().getName());
                });
            }
    

    输出:每个任务都会起一个线程,无限扩大

    pool-1-thread-1
    pool-1-thread-2
    pool-1-thread-3
    pool-1-thread-4
    pool-1-thread-5
    

    2、newFixedThreadPool

    • 它是一种固定大小的线程池(corePoolSize、maximunPoolSize都为用户设定的线程数量nThreads);
    • 阻塞队列采用了LinkedBlockingQueue,它是一个无界队列(实际线程数量将永远维持在nThreads),因此永远不可能拒绝任务;

    代码示例:

            ExecutorService fixedPool = Executors.newFixedThreadPool(3);
            for(int i=0; i<5; i++){
                fixedPool.execute(() -> {
                    System.out.println(Thread.currentThread().getName());
                });
            }
    

    输出:

    pool-2-thread-1
    pool-2-thread-3
    pool-2-thread-1
    pool-2-thread-2
    pool-2-thread-3
    

    固定线程池大小为3,需要5个线程,所以前3个线程就存在线程复用的情况。

    当任务执行存在时延时,前三个线程就不会出现线程复用的情况了:

            ExecutorService fixedPool = Executors.newFixedThreadPool(3);
            for(int i=0; i<5; i++){
                fixedPool.execute(() -> {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+":"+System.currentTimeMillis()/1000);
                });
            }
    

    输出:任务耗时一秒,前三个线程没有复用

    pool-1-thread-3:1631157921
    pool-1-thread-1:1631157921
    pool-1-thread-2:1631157921
    pool-1-thread-1:1631157922
    pool-1-thread-2:1631157922
    

    3、ScheduledThreadPool

    • 它用来处理延时任务或定时任务;
    • 它采用DelayQueue存储等待的任务,是一个无界队列,内部封装了一个PriorityQueue,它会根据time的先后时间排序,若time相同则根据sequenceNumber排序;
    • 工作过程:任务线程会从DelayQueue取已经到期的任务去执行,执行结束后重新设置任务的到期时间,再次放回DelayQueue。

    代码示例:

    (1)定时任务:scheduleAtFixedRate

    • 表示上一个任务开始和下一个任务开始之间,间隔一个period;
    • 如果上一个任务执行完毕,则当前任务立即执行,如果上一个任务没有执行完毕,则需要等上一个任务执行完毕后立即执行。

    a)任务执行时间小于period,则以period定时处理任务

    ScheduledExecutorService schedPool = Executors.newScheduledThreadPool(3);
    for (int i = 0; i < 3; i++) {
        schedPool.scheduleAtFixedRate(() ->{
            System.out.println(Thread.currentThread().getName()+":"+System.currentTimeMillis()/1000);
        }, 0,3, TimeUnit.SECONDS);
    
    }
    

    输出:

    pool-1-thread-1:1631176308
    pool-1-thread-1:1631176308
    pool-1-thread-1:1631176308
    
    pool-1-thread-1:1631176311
    pool-1-thread-3:1631176311
    pool-1-thread-1:1631176311
    
    pool-1-thread-3:1631176314
    pool-1-thread-1:1631176314
    pool-1-thread-2:1631176314
    

    b)若任务执行时间大于period,则以执行时间定时处理任务

    ScheduledExecutorService schedPool = Executors.newScheduledThreadPool(3);
    for (int i = 0; i < 3; i++) {
        schedPool.scheduleAtFixedRate(() ->{
            System.out.println(Thread.currentThread().getName()+":"+System.currentTimeMillis()/1000);
            try {
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, 0,3, TimeUnit.SECONDS);
    }
    

    输出:

    pool-1-thread-2:1631176413
    pool-1-thread-3:1631176413
    pool-1-thread-1:1631176413
    
    pool-1-thread-2:1631176417
    pool-1-thread-1:1631176417
    pool-1-thread-3:1631176417
    
    pool-1-thread-3:1631176421
    pool-1-thread-2:1631176421
    pool-1-thread-1:1631176421
    

    (2)延时任务:scheduleWithFixedDelay

    • 表示上一个任务结束和下一个任务开始之间,时间间隔为一个delay

    任务执行时间为4秒,延时为3秒,所以每个任务之间间隔7秒

    ScheduledExecutorService schedPool = Executors.newScheduledThreadPool(3);
    for (int i = 0; i < 3; i++) {
        schedPool.scheduleWithFixedDelay(() ->{
            System.out.println(Thread.currentThread().getName()+":"+System.currentTimeMillis()/1000);
            try {
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, 0,3, TimeUnit.SECONDS);
    }
    

    输出:

    pool-1-thread-1:1631176156
    pool-1-thread-3:1631176156
    pool-1-thread-2:1631176156
    
    pool-1-thread-3:1631176163
    pool-1-thread-1:1631176163
    pool-1-thread-2:1631176163
    
    pool-1-thread-1:1631176170
    pool-1-thread-2:1631176170
    pool-1-thread-3:1631176170
    

    4、 SingleThreadExecutor

    • 它只会创建一条工作线程处理任务;
    • 采用的阻塞队列为LinkedBlockingQueue;

    相关文章

      网友评论

        本文标题:线程池使用场景

        本文链接:https://www.haomeiwen.com/subject/jydiwltx.html