线程池学习笔记

java线程池

      • 官方文档
      • 核心参数
        • 参数说明:
          • 源码注释
      • java 内置的默认线程池实现
          • newFixedThreadPool 可以生成固定大小的线程池;
          • newCachedThreadPool 可以生成一个无界、可以自动回收的线程池;
          • newSingleThreadScheduledExecutor 可以生成一个单个线程的线程池;
          • newScheduledThreadPool 还可以生成支持周期任务的线程池。
          • newWorkStealingPool [官方文档](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newWorkStealingPool--)
    • 线程池基本使用
      • 为什么不要使用默认实现
      • 怎么自己实现
            • Java线程池的分析和使用
            • 深入理解Java线程池:ThreadPoolExecutor
            • Java线程池实现原理及其在美团业务中的实践
          • 定时任务线程池
          • 计算密集型
          • io密集型
      • springconfig定义全局线程池
      • execute submit
    • 源码阅读
      • execute
        • addwork
        • worker
      • summit
        • submit
      • AQS
      • worker
      • forkjion https://www.toutiao.com/i6906423455508382220/?tt_from=weixin&utm_campaign=client_share&wxshare_count=1×tamp=1608087445&app=news_article&utm_source=weixin&utm_medium=toutiao_android&use_new_style=1&req_id=2020121610572501013105707744A19998&group_id=6906423455508382220$a
      • task featureTask ForkJoinTask https://www.cnblogs.com/dolphin0520/p/3949310.html
      • CompletableFuture https://stackoverflow.com/questions/30559707/completablefuture-from-callable https://my.oschina.net/u/3703858/blog/1799785
      • 多线程引发的问题 ThreadLocal失效 sqlsesion独立 mybatispageHelper 数据库事物失效 mdc问题
      • hystrix 线程池的使用

官方文档

核心参数

// 线程池构造方法
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)

参数说明:

源码注释
/**
     * Creates a new {@code ThreadPoolExecutor} with the given initial
     * parameters and default thread factory and rejected execution handler.
     * It may be more convenient to use one of the {@link Executors} factory
     * methods instead of this general purpose constructor.
     *
     * @param corePoolSize the number of threads to keep in the pool, even
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
     * @param maximumPoolSize the maximum number of threads to allow in the
     *        pool
     * @param keepAliveTime when the number of threads is greater than
     *        the core, this is the maximum time that excess idle threads
     *        will wait for new tasks before terminating.
     * @param unit the time unit for the {@code keepAliveTime} argument
     * @param workQueue the queue to use for holding tasks before they are
     *        executed.  This queue will hold only the {@code Runnable}
     *        tasks submitted by the {@code execute} method.
     * @throws IllegalArgumentException if one of the following holds:
* {@code corePoolSize < 0}
* {@code keepAliveTime < 0}
* {@code maximumPoolSize <= 0}
* {@code maximumPoolSize < corePoolSize} * @throws NullPointerException if {@code workQueue} is null */
  • corePoolSize(线程池的基本线程数): the number of threads to keep in the pool, even if they are idle, unless allowCoreThreadTimeOut is set.当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。如果调用了线程池的prestartAllCoreThreads方法,线程池会提前创建并启动所有基本线程。
  • maximumPoolSize(线程池最大线程数): the maximum number of threads to allow in the pool.线程池允许创建的最大线程数。如果任务队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。值得注意的是如果使用了无界的任务队列这个参数就没什么效果。

线程池有两个线程数的设置,一个为核心池线程数(corePoolSize),一个为最大线程数(maximumPoolSize)。
在创建了线程池后,默认情况下,线程池中并没有任何线程,等到有任务来才创建线程去执行任务,除非调用了prestartAllCoreThreads()或者prestartCoreThread()方法
当创建的线程数等于 corePoolSize 时,会加入设置的阻塞队列。当队列满时,会创建线程执行任务直到线程池中的数量等于maximumPoolSize。

  • keepAliveTime(线程活动保持时间):when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.线程池的工作线程空闲后,保持存活的时间。所以如果任务很多,并且每个任务执行的时间比较短,可以调大这个时间,提高线程的利用率。

  • TimeUnit(线程活动保持时间的单位):the time unit for the keepAliveTime argument. 可选的单位有天(DAYS),小时(HOURS),分钟(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。

  • workQueue(任务队列):the queue to use for holding tasks before they are executed. This queue will hold only the Runnable tasks submitted by the execute method.用于保存等待执行的任务的阻塞队列。 可以选择以下几个阻塞队列。

  • ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。

  • LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。

  • SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。

  • PriorityBlockingQueue:一个具有优先级的无限阻塞队列。

  • DelayQueue: 一个使用优先级队列实现的无界阻塞队列。

  • ThreadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。

  • RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。以下是JDK1.5提供的四种策略。
     -  AbortPolicy:直接抛出异常。
     -  CallerRunsPolicy:只用调用者所在线程来运行任务。
     -  DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。
     -  DiscardPolicy:不处理,丢弃掉。
      当然也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略。如记录日志或持久化不能处理的任务。
      由此可见,创建一个线程所需的参数很多,线程池为我们提供了类Executors的静态工厂方法以创建不同类型的线程池。

java 内置的默认线程池实现

newFixedThreadPool 可以生成固定大小的线程池;
 /**
     * Creates a thread pool that reuses a fixed number of threads
     * operating off a shared unbounded queue.  At any point, at most
     * {@code 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());
    }

newCachedThreadPool 可以生成一个无界、可以自动回收的线程池;

/**
     * Creates a thread pool that creates new threads as needed, but
     * will reuse previously constructed threads when they are
     * available.  These pools will typically improve the performance
     * of programs that execute many short-lived asynchronous tasks.
     * Calls to {@code execute} will reuse previously constructed
     * threads if available. If no existing thread is available, a new
     * thread will be created and added to the pool. Threads that have
     * not been used for sixty seconds are terminated and removed from
     * the cache. Thus, a pool that remains idle for long enough will
     * not consume any resources. Note that pools with similar
     * properties but different details (for example, timeout parameters)
     * may be created using {@link ThreadPoolExecutor} constructors.
     *
     * @return the newly created thread pool
     */
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue());
    }

newSingleThreadScheduledExecutor 可以生成一个单个线程的线程池;
  /**
     * Creates an Executor that uses a single worker thread operating
     * off an unbounded queue. (Note however that if this single
     * thread terminates due to a failure during execution prior to
     * shutdown, a new one will take its place if needed to execute
     * subsequent tasks.)  Tasks are guaranteed to execute
     * sequentially, and no more than one task will be active at any
     * given time. Unlike the otherwise equivalent
     * {@code newFixedThreadPool(1)} the returned executor is
     * guaranteed not to be reconfigurable to use additional threads.
     *
     * @return the newly created single-threaded Executor
     */
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue()));
    }

可以看做是线程队列

newScheduledThreadPool 还可以生成支持周期任务的线程池。
 /**
     * Creates a single-threaded executor that can schedule commands
     * to run after a given delay, or to execute periodically.
     * (Note however that if this single
     * thread terminates due to a failure during execution prior to
     * shutdown, a new one will take its place if needed to execute
     * subsequent tasks.)  Tasks are guaranteed to execute
     * sequentially, and no more than one task will be active at any
     * given time. Unlike the otherwise equivalent
     * {@code newScheduledThreadPool(1)} the returned executor is
     * guaranteed not to be reconfigurable to use additional threads.
     * @return the newly created scheduled executor
     */
    public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1));
    }


可以实现定时执行,延时执行

newWorkStealingPool 官方文档
 /**
     * Creates a work-stealing thread pool using all
     * {@link Runtime#availableProcessors available processors}
     * as its target parallelism level.
     * @return the newly created thread pool
     * @see #newWorkStealingPool(int)
     * @since 1.8
     */
    public static ExecutorService newWorkStealingPool() {
        return new ForkJoinPool
            (Runtime.getRuntime().availableProcessors(),
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }

ps : 这个是1.8 以后新的api 没用过 大部分博客也没有说过 基于fork-join 字面意思应该是可以迅速的创建新的线程,更高的性能吧。不了解原理和使用场景,回头看先

线程池基本使用

 public void uploadTs() throws ExecutionException, InterruptedException {
        
        
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        exeUpload(executorService);
        
        
        executorService = Executors.newSingleThreadExecutor();
        exeUpload(executorService);
        
        
         executorService = Executors.newCachedThreadPool();
        exeUpload(executorService);
        
           ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
        long initialDelay1 = 1;
        long period1 = 1;
        scheduledExecutorService.scheduleAtFixedRate(
                new HandlerScore(new HashMap(), "url", 1),
                initialDelay1,
                period1,
                TimeUnit.MINUTES);
        exeUpload(executorService);
        executorService.shutdown();

         executorService = Executors.newWorkStealingPool();
        exeUpload(executorService);
        
        

    }

    private void exeUpload(ExecutorService executorService) throws InterruptedException, ExecutionException {
        String url = "uploadUrl";
        HashMap params = new HashMap<>();
        List> res = new ArrayList<>();
        for (int i = 0; i < 50; i++) {
            UploadPic myThread = new UploadPic(params, url, i);
            Future submit = executorService.submit(myThread);
            res.add(submit);
        }
        for (Future re : res) {
            String s = re.get();
        }
    }


    @Data
    @AllArgsConstructor
    class UploadPic implements Callable {

        private Map params;
        private String url;
        private Integer numT;

        @Override
        public String call() throws Exception {

            return "path_"+numT;
        }
    }


为什么不要使用默认实现

来源 java开发规范泰山版

    1. 【强制】创建线程或线程池时请指定有意义的线程名称,方便出错时回溯。
      正例:自定义线程工厂,并且根据外部特征进行分组,比如,来自同一机房的调用,把机房编号赋值给
      whatFeaturOfGroup
public class UserThreadFactory implements ThreadFactory { private final String namePrefix;
private final AtomicInteger nextId = new AtomicInteger(1);
// 定义线程组名称,在 jstack 问题排查时,非常有帮助
UserThreadFactory(String whatFeaturOfGroup) {
namePrefix = "From UserThreadFactory's " + whatFeaturOfGroup + "-Worker-";
}
@Override
public Thread newThread(Runnable task) {
String name = namePrefix + nextId.getAndIncrement(); Thread thread = new Thread(null, task, name, 0, false); System.out.println(thread.getName());
return thread;
} }
    1. 【强制】线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。 说明:线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源的开销,解决资源不足的问题。 如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题。
    1. 【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这 样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。 说明:Executors 返回的线程池对象的弊端如下:
      FixedThreadPool SingleThreadPool: nteger.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
      CachedThreadPool:
      Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。1

怎么自己实现

Java线程池的分析和使用
深入理解Java线程池:ThreadPoolExecutor
Java线程池实现原理及其在美团业务中的实践
定时任务线程池
  • 需要注意的是corepoolsize 和队列的配置,长任务可能会填满线程池,导致线程不执行的假象,实际被放到阻塞队列中等待池资源释放。
  • ThreadPoolTaskExecutor 难以拓展,在生产环境中很难监控任务状态。
  • 如果需要定时任务监控及调度的话 可以考虑 xxl-job来实现任务调度,自带高可用解决方案。elasticjob也很优秀,分布式调度实现的很好,但是很久没有更新了,前几天打开发现加入了apche, 版本已经更新到了3.0。如果任务比较大,对时间有硬要求可以考虑elasticjob。
计算密集型

应用需要非常多的 CPU 计算资源,在多核 CPU 时代,我们要让每一个 CPU 核心都参与计算,将 CPU 的性能充分利用起来,这样才算是没有浪费服务器配置,如果在非常好的服务器配置上还运行着单线程程序那将是多么重大的浪费。对于计算密集型的应用,完全是靠 CPU 的核数来工作,所以为了让它的优势完全发挥出来,避免过多的线程上下文切换,比较理想方案是:
线程数 = CPU核数+1
也可以设置成 CPU核数2 ,这还是要看JDK的使用版本,以及CPU配置(服务器的CPU有超线程)。对于JDK1.8来说,里面增加了一个并行计算,计算密集型的较理想 线程数 = CPU内核线程数2

io密集型

IO 密集型的应用,我们现在做的开发大部分都是 WEB 应用,涉及到大量的网络传输,不仅如此,与数据库,与缓存间的交互也涉及到 IO ,一旦发生 IO ,线程就会处于等待状态,当 IO 结束,数据准备好后,线程才会继续执行。因此从这里可以发现,对于 IO 密集型的应用,我们可以多设置一些线程池中线程的数量,这样就能让在等待 IO 的这段时间内,线程可以去做其它事,提高并发处理效率。
那么这个线程池的数据量是不是可以随便设置呢?当然不是的,请一定要记得,线程上下文切换是有代价的。目前总结了一套公式,对于 IO 密集型应用:
线程数 = CPU核心数/(1-阻塞系数)
这个阻塞系数一般为 0.8~0.9 之间,也可以取 0.8 或者 0.9 。套用公式,对于双核 CPU 来说,它比较理想的线程数就是 20 ,当然这都不是绝对的,需要根据实际情况以及实际业务来调整。
final int poolSize = ( int ) (cpuCore/(1-0.9))

实际生产中, 服务的粒度大部分是比较粗的,服务模块是以业务为单位考虑的. 既有io密集型接口(sql连接执行,第三方调用),又有计算密集型接口(规则判断)可能需要队服务进行压测才可以获得比较准确的数据

springconfig定义全局线程池


/**
 *
 * @author chenqi
 * @description
 * @data 2020/9/3
 */
@Slf4j
@Configuration

public class SfaThreadPoolConfig  {

    @Autowired
    BeanFactory beanFactory;

    @Value("${spring.application.name}")
    private String prefix;

    /**
     * 计算密集型任务
     */
    @Value("${spring.threadPoolExecutor.calculation.coreSize: 0}")
    private int calculationCore;

    @Value("${spring.threadPoolExecutor.calculation.maxSize: 6}")
    private int calculationMaxSize;

    @Value("${spring.threadPoolExecutor.calculation.queueSize: 100}")
    private int calculationQueueSize;

    @Value("${spring.threadPoolExecutor.calculation.unit:SECONDS}")
    private String calculationUnit;

    @Value("${spring.threadPoolExecutor.calculation.keepAliveTime: 300}")
    private int calculationKeepAliveTime;


    /**
     * io密集型任务
     */

    @Value("${spring.threadPoolExecutor.Io.coreSize: 10}")
    private int ioCore;

    @Value("${spring.threadPoolExecutor.Io.maxSize: 300}")
    private int ioMaxSize;

    @Value("${spring.threadPoolExecutor.Io.queueSize: 1000}")
    private int ioQueueSize;

    @Value("${spring.threadPoolExecutor.Io.unit:SECONDS}")
    private String ioUnit;

    @Value("${spring.threadPoolExecutor.Io.keepAliveTime: 600}")
    private int ioKeepAliveTime;




    /**
     * 计算型
     *
     * @return
     */

    @Bean("calculationThreadPool")
    public Executor getPool() {
        FeiHeThreadPoolExecutor calculationThreadPool = new FeiHeThreadPoolExecutor(calculationCore,
                calculationMaxSize,
                calculationKeepAliveTime,
                TimeUnit.valueOf(calculationUnit.toUpperCase()),
                new ArrayBlockingQueue<>(calculationQueueSize),
                prefix);

        return calculationThreadPool;
    }
    /**
     * io型
     *
     * @return
     */

    @Bean("ioThreadPool")
    public Executor getIoPool() {
        FeiHeThreadPoolExecutor ioThreadPool = new FeiHeThreadPoolExecutor(ioCore,
                ioMaxSize,
                ioKeepAliveTime,
                TimeUnit.valueOf(ioUnit.toUpperCase()),
                new ArrayBlockingQueue<>(ioQueueSize),
                prefix);
        return ioThreadPool;
    }


    public class FeiHeThreadPoolExecutor extends ThreadPoolExecutor {
        // 保存任务开始执行的时间,当任务结束时,用任务结束时间减去开始时间计算任务执行时间
        private ConcurrentHashMap startTimes;

        // 线程池名称,以业务名称命名,方便区分
        private String poolName;

        /**
         * 调用父类的构造方法,并初始化HashMap和线程池名称
         *
         * @param corePoolSize    线程池核心线程数
         * @param maximumPoolSize 线程池最大线程数
         * @param keepAliveTime   线程的最大空闲时间
         * @param unit            空闲时间的单位
         * @param workQueue       保存被提交任务的队列
         * @param poolName        线程池名称
         */
        public FeiHeThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue,
                                       String poolName) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, new EventThreadFactory(poolName));
            this.startTimes= new ConcurrentHashMap<>(maximumPoolSize);
            this.poolName=poolName;

        }

        /**
         * 任务执行之前,记录任务开始时间
         */
        @Override
        protected void beforeExecute(Thread t, Runnable r) {
            super.beforeExecute(t,r);
            startTimes.put(String.valueOf(r.hashCode()), System.currentTimeMillis());
        }



        /**
         * 任务执行之后,计算任务结束时间
         */
        @Override
        protected void afterExecute(Runnable r, Throwable t) {
            super.afterExecute(r,t);
            long diff = System.currentTimeMillis() - startTimes.remove(String.valueOf(r.hashCode()));
            // 统计任务耗时、初始线程数、核心线程数、正在执行的任务数量、已完成任务数量、任务总数、队列里缓存的任务数量、池中存在的最大线程数、最大允许的线程数、线程空闲时间、线程池是否关闭、线程池是否终止
            log.info(String.format(this.poolName
                            + "-pool-monitor: Duration: %d ms, PoolSize: %d, CorePoolSize: %d, Active: %d, Completed: %d, Task: %d, Queue: %d, LargestPoolSize: %d, MaximumPoolSize: %d,  KeepAliveTime: %d, isShutdown: %s, isTerminated: %s",
                    diff, this.getPoolSize(), this.getCorePoolSize(), this.getActiveCount(), this.getCompletedTaskCount(), this.getTaskCount(),
                    this.getQueue().size(), this.getLargestPoolSize(), this.getMaximumPoolSize(), this.getKeepAliveTime(TimeUnit.MILLISECONDS),
                    this.isShutdown(), this.isTerminated()));
        }


    }


    /**
     * 生成线程池所用的线程,只是改写了线程池默认的线程工厂,传入线程池名称,便于问题追踪
     */
    static class EventThreadFactory 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;

        /**
         * 初始化线程工厂
         *
         * @param poolName 线程池名称
         */
        EventThreadFactory(String poolName) {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
            namePrefix = poolName + "-pool-" + poolNumber.getAndIncrement() + "-thread-";
        }

        @Override
        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;
        }
    }


}



execute submit

源码阅读

execute

execute

  • 向线程池添加一个线程,不接收返回.如果线程池触发拒绝策略则执行拒绝策略

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    int c = ctl.get();
    // 1. 判断core是否塞得下
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    // 2. 判断workQueue是否塞得下
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        if (! isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    // 3. addWorker中判断max是否塞得下
    else if (!addWorker(command, false))
        reject(command);
}

  • 在这里ctl是一个设计非常精巧的状态管理器,它其实是一个AtomicInteger,它利用int的前三位来存储当前线程池的状态(RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED),后29位用来存储线程数量。
  • 在这段代码中,我们可以看到对线程的执行策略分为了三个部分:1. core部分 2. workQueue部分 3. max部分。其中workQueue部分比较直观,就是直接调用workQueue.offer(command)将线程加入了待执行队列。那么接下来需要关注的是addWorker()方法。

addwork

private boolean addWorker(Runnable firstTask, boolean core) {
    // 判断firstTask能否被执行
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&  // SHUTDOWN状态不会执行新线程,但是可以执行workQueue中的线程
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;

        for (;;) {
            int wc = workerCountOf(c);
            if (wc >= CAPACITY ||  // 最多支持2^29-1个线程
                wc >= (core ? corePoolSize : maximumPoolSize))  // 此处判断max是否塞得下
                return false;
            if (compareAndIncrementWorkerCount(c)) // 利用CAS防止并发问题
                break retry;
            c = ctl.get();
            if (runStateOf(c) != rs)
                continue retry;
        }
    }

    // 执行新的线程
    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        w = new Worker(firstTask);
        final Thread t = w.thread;
        if (t != null) {
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {    // 尝试添加线程
                int rs = runStateOf(ctl.get());

                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) { // SHUTDOWN状态不会执行新线程,但是可以执行workQueue中的线程
                    if (t.isAlive())
                        throw new IllegalThreadStateException();
                    workers.add(w);
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            if (workerAdded) {
                t.start();         // 执行线程
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

  • addWorker()这段代码看起来比较复杂,但是如果去除掉一些细节和并发安全相关的代码,整体的代码逻辑就是判断线程是否可以执行,如果可以执行则新建线程执行。在这段代码中,我们可以看到我们的线程被封装到了一个叫做Worker的类中,接下来,我们继续探究Worker的源码。

worker

  /**
          * Creates with given first task and thread from ThreadFactory.
          * @param firstTask the first task (null if none)
          */
         Worker(Runnable firstTask) {
             setState(-1); // inhibit interrupts until runWorker
             this.firstTask = firstTask;
             this.thread = getThreadFactory().newThread(this);
         }

// 调用runworker
public void run() {
    runWorker(this);
}

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock();
    boolean completedAbruptly = true;
    try {
        while (task != null || (task = getTask()) != null) {   // 获取Task
            w.lock();
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
                beforeExecute(wt, task);  // 空方法,扩展使用
                Throwable thrown = null;
                try {
                    task.run();     // 执行Task
                } catch (RuntimeException x) {
                    thrown = x; throw x;
                } catch (Error x) {
                    thrown = x; throw x;
                } catch (Throwable x) {
                    thrown = x; throw new Error(x);
                } finally {
                    afterExecute(task, thrown);   // 空方法,扩展使用
                }
            } finally {
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        processWorkerExit(w, completedAbruptly);
    }
}


summit

submit

  • 向线程池添加一个线程,接收返回 。如果线程池触发拒绝策略则执行拒绝策略。
  • 线程要实现callable接口,返回feature,feature.get()是阻塞的,直到返回结果或者抛出异常。

AQS

  • 线程池实现 retrentlock readwertelock stamplock
  • AQS

worker

forkjion https://www.toutiao.com/i6906423455508382220/?tt_from=weixin&utm_campaign=client_share&wxshare_count=1×tamp=1608087445&app=news_article&utm_source=weixin&utm_medium=toutiao_android&use_new_style=1&req_id=2020121610572501013105707744A19998&group_id=6906423455508382220$a

task featureTask ForkJoinTask https://www.cnblogs.com/dolphin0520/p/3949310.html

CompletableFuture https://stackoverflow.com/questions/30559707/completablefuture-from-callable https://my.oschina.net/u/3703858/blog/1799785

多线程引发的问题 ThreadLocal失效 sqlsesion独立 mybatispageHelper 数据库事物失效 mdc问题

hystrix 线程池的使用

todo disrput,netty , 数据库连接池,

CompletableFuture 类可以实现类似于 Javascript 的 promise-chain,内部就是使用 ForkJoinPool 来实现的

ForkJoinPool

我会结合 ForkJoinPool 的作者 Doug Lea 的论文——《A Java Fork/Join Framework》,尽可能通俗地解释 Fork/Join Framework 的原理。

你可能感兴趣的:(java基础)