• java线程池入门


    前言

    使用线程池有以下好处:

    • 创建销毁线程消耗系统资源,线程池可以复用已创建的线程。
    • 控制并发的数量,并发数量过多,可能导致资源不足,服务器崩溃。
    • 对线程进行统一管理。

    简单使用

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.LinkedBlockingQueue;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.ThreadPoolExecutor.AbortPolicy;
    import java.util.concurrent.TimeUnit;
    
    public class Client {
    
      public static void main(String[] args) {
        ExecutorService executorService = new ThreadPoolExecutor(
            5,
            10,
            60,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(),
            Executors.defaultThreadFactory(),
            new AbortPolicy()
        );
        executorService
            .execute(() -> System.out.println(Thread.currentThread().getName() + " is running"));
        executorService.shutdown();
      }
    
    }
    

    参数分析

    线程池的核心实现为ThreadPoolExecutor类,

    public ThreadPoolExecutor(int corePoolSize,
                                  int maximumPoolSize,
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue<Runnable> workQueue,
                                  ThreadFactory threadFactory,
                                  RejectedExecutionHandler handler) {
    }
    

    一共有7大重要参数

    • corePoolSize
    表示核心线程数量,线程池中有两种线程,核心线程和非核心线程(临时工)
    
    • maximumPoolSize
    表示线程总数量,核心数+非核心数
    
    • keepAliveTime
    表示非核心线程闲置超时时长,超过了这个时间,线程就会被回收,如果设置了allowCoreThreadTimeOut(true),也会作用于核心线程
    
    • unit
    时间单位,主要有时(HOURS),分(MINUTES),秒(SECONDS),毫秒(MILLISECONDS),微妙(MICROSECONDS),纳秒(NANOSECONDS)
    
    • workQueue
    任务队列,当任务数量超过核心线程数时,就会将任务添加到任务队列中。
    常用的队列类型有
    1.LinkedBlockingQueue,阻塞队列,底层实现为链表,默认大小为Integer.MAX_VALUE,可以设置大小
    2.ArrayBlockingQueue,阻塞队列,底层实现为数组,必须指定大小
    3.SynchronousQueue,同步队列,容量为0,添加操作必须等待消费操作,反之亦然
    4.DelayQueue,延时队列,只有到达了延时时间,才能从队列中获取到
    
    • threadFactory
      表示创建线程的工厂,默认实现为
    /**
         * The default thread factory.
         */
        private static class DefaultThreadFactory implements ThreadFactory {
            private static final AtomicInteger poolNumber = new AtomicInteger(1);
            private final ThreadGroup group;
            private final AtomicInteger threadNumber = new AtomicInteger(1);
            private final String namePrefix;
    
            DefaultThreadFactory() {
                SecurityManager s = System.getSecurityManager();
                group = (s != null) ? s.getThreadGroup() :
                                      Thread.currentThread().getThreadGroup();
                namePrefix = "pool-" +
                              poolNumber.getAndIncrement() +
                             "-thread-";
            }
    
            public Thread newThread(Runnable r) {
                Thread t = new Thread(group, r,
                                      namePrefix + threadNumber.getAndIncrement(),
                                      0);
                if (t.isDaemon())
                    t.setDaemon(false);
                if (t.getPriority() != Thread.NORM_PRIORITY)
                    t.setPriority(Thread.NORM_PRIORITY);
                return t;
            }
        }
    
    • handler
      表示拒绝策略,当任务数量大于线程最大容量时,就会执行拒绝策略,有4种实现
    1.AbortPolicy,直接抛异常
    2.DiscardPolicy,直接丢弃,不抛异常
    3.DiscardOldestPolicy,丢弃任务队列头部元素,重新尝试执行
    4.CallerRunsPolicy,由调用线程来执行
    

    上述7个参数,前5个为必须,后2个非必须。

    线程池的处理流程

    1. 线程总数量 < corePoolSize,⽆论线程是否空闲,都会新建⼀个核心线程执⾏任务。
    2. 线程总数量 >= corePoolSize时,新来的线程任务会进⼊任务队列中等待,然后空闲的核心线程会依次去缓存队列中取任务来执行(体现了线程复用)。
    3. 当缓存队列满了,说明这个时候任务已经多到爆棚,需要⼀些“临时⼯”来执⾏ 这些任务了。于是会创建⾮核心线程去执行这个任务。
    4. 缓存队列满了,且总线程数达到了maximumPoolSize,则会执行拒绝策略。

    线程池状态

    线程池一共有5种状态,

    1. RUNNING,线程池创建后为RUNNING状态
    2. SHUTDOWN,调用shutdown()方法后处于SHUTDOWN状态,此时不能接收新任务,中断所有未执行的线程,等待任务队列中任务完成。
    3. STOP,调用shutdownNow()方法后处于STOP状态,此时不能接收新任务,中断所有正在执行的线程,任务队列中未执行任务全部丢弃。
    4. TIDYING,当所有任务已终止,线程池中任务数量为0,此时状态为TIDYING
    5. TERMINATED,执行完terminated()方法,状态由TIDYING变成TERMINATED

    4种常用的线程池

    jdk提供了一个工具类Executors,简化我们创建线程池的过程

    • newCachedThreadPool
    public static ExecutorService newCachedThreadPool() {
            return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                          60L, TimeUnit.SECONDS,
                                          new SynchronousQueue<Runnable>());
        }
    

    不会创建核心线程,全部为非核心线程(临时工),超过60S回收。适合执行有很多短时间的任务。

    • newFixedThreadPool
    public static ExecutorService newFixedThreadPool(int nThreads) {
            return new ThreadPoolExecutor(nThreads, nThreads,
                                          0L, TimeUnit.MILLISECONDS,
                                          new LinkedBlockingQueue<Runnable>());
        }
    

    只创建核心线程,不创建非核心线程,超过数量全部进任务队列。

    • newSingleThreadExecutor
    public static ExecutorService newSingleThreadExecutor() {
            return new FinalizableDelegatedExecutorService
                (new ThreadPoolExecutor(1, 1,
                                        0L, TimeUnit.MILLISECONDS,
                                        new LinkedBlockingQueue<Runnable>()));
        }
    

    只有一个核心线程,和 newFixedThreadPool(1) 的区别为,newFixedThreadPool(1)创建的线程池是可以重新配置的,如重新设置核心线程数量,而newSingleThreadExecutor()创建的线程池不能重新配置。

    • newScheduledThreadPool
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
            return new ScheduledThreadPoolExecutor(corePoolSize);
    }
    public ScheduledThreadPoolExecutor(int corePoolSize) {
            super(corePoolSize, Integer.MAX_VALUE,
                  DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
                  new DelayedWorkQueue());
    }
    

    ScheduledThreadPoolExecutor继承于ThreadPoolExecutor,支持定时任务及周期性任务。

    参考

    线程池,这一篇或许就够了
    Java线程池实现原理与源码解析(jdk1.8)

  • 相关阅读:
    使用java写一个小白计算器
    UVALive 6911 Double Swords (Set,贪心,求区间交集)
    UVALive 6910 Cutting Tree(并查集应用)
    Gym 101102C Bored Judge(set--结构体集合)
    有序链表和顺序表
    Gym 101102B The Little Match Girl(贪心+规律)
    UVALive 7070 The E-pang Palace(暴力)
    数据库系统实现 第二章 数据存储
    数据库系统实现 第一章 DBMS实现概述
    数据库系统实现 第六章 查询执行
  • 原文地址:https://www.cnblogs.com/strongmore/p/14879439.html
Copyright © 2020-2023  润新知