线程池

线程池

通过例子理解

  • 例1
package com.example.test;

import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.concurrent.*;

/**
 * 核心线程数:5,最大线程数:10,有界阻塞队列长度:5
 *
 * @author mdl
 * @date 2020/5/14 14:21
 */
public class ThreadPoolTest {

    public static void main(String[] args) {
        int corePoolSize = 5;
        int maximumPoolSize = 10;
        int queueSize = 5;

        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("thread-call-runner-%d").build();
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(queueSize);
        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 0, TimeUnit.MILLISECONDS,
                workQueue, namedThreadFactory, new MyIgnorePolicy());

        for(int i =0; i< 10 ;i++){
            executor.submit(new Handle());
        }
        // 效果:打印了前5个任务,10s后打印后5个任务
        // 结论1:来了5个任务(假定任务执行时间较长),这时再来任务,将进入阻塞队列,核心线程空闲时处理
        // ----------------------------------------------------

    }

    public static class MyIgnorePolicy implements RejectedExecutionHandler {

        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            System.err.println(r.toString() + " rejected");
        }
    }


    static class Handle implements Runnable{

        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + "--- executor...");
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

image-20200514145103136

红框内的再10s后出现的

结论:来了5个任务(假定任务执行时间较长),这时再来任务,将进入阻塞队列,核心线程空闲时处理

  • 例2

    package com.example.test;
    
    import com.google.common.util.concurrent.ThreadFactoryBuilder;
    
    import java.util.concurrent.*;
    
    /**
     * 核心线程数:5,最大线程数:10,有界阻塞队列长度:5
     *
     * @author mdl
     * @date 2020/5/14 14:21
     */
    public class ThreadPoolTest {
    
        public static void main(String[] args) {
            int corePoolSize = 5;
            int maximumPoolSize = 10;
            int queueSize = 5;
    
            ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("thread-call-runner-%d").build();
            BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(queueSize);
            ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 0, TimeUnit.MILLISECONDS,
                    workQueue, namedThreadFactory, new MyIgnorePolicy());
    
    //        for(int i =0; i< 10 ;i++){
    //            executor.submit(new Handle());
    //        }
            // 效果:打印了前5个任务,10s后打印后5个任务
            // 结论1:来了5个任务(假定任务执行时间较长),这时再来任务,将进入阻塞队列,核心线程空闲时处理
            // ----------------------------------------------------
            for(int i =0; i< 15 ;i++){
                executor.submit(new Handle());
            }
            // 效果:先打印了10个线程执行,10s后打印5个
            // 结论:第1~5进来的任务由核心线程执行,第6~10将进入阻塞任务队列,第11~15个任务由临时线程执行
            // 核心线程或者临时线程空闲出来后去取阻塞任务队列里的任务执行
        }
    
        public static class MyIgnorePolicy implements RejectedExecutionHandler {
    
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                System.err.println(r.toString() + " rejected");
            }
        }
        
        static class Handle implements Runnable{
    
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "--- executor...");
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    image-20200514145729556

红框里的10s后才显示

结论:第1~5进来的任务由核心线程执行,第6~10将进入阻塞任务队列,第11~15个任务由临时线程执行

核心线程或者临时线程空闲出来后去取阻塞任务队列里的任务执行

  • 例3

    package com.example.test;
    
    import com.google.common.util.concurrent.ThreadFactoryBuilder;
    
    import java.util.concurrent.*;
    
    /**
     * 核心线程数:5,最大线程数:10,有界阻塞队列长度:5
     *
     * @author mdl
     * @date 2020/5/14 14:21
     */
    public class ThreadPoolTest {
    
        public static void main(String[] args) {
            int corePoolSize = 5;
            int maximumPoolSize = 10;
            int queueSize = 5;
    
            ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("thread-call-runner-%d").build();
            BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(queueSize);
            ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 0, TimeUnit.MILLISECONDS,
                    workQueue, namedThreadFactory, new MyIgnorePolicy());
    
    //        for(int i =0; i< 10 ;i++){
    //            executor.submit(new Handle());
    //        }
            // 效果:打印了前5个任务,10s后打印后5个任务
            // 结论1:来了5个任务(假定任务执行时间较长),这时再来任务,将进入阻塞队列,核心线程空闲时处理
            // ----------------------------------------------------
    //        for(int i =0; i< 15 ;i++){
    //            executor.submit(new Handle());
    //        }
            // 效果:先打印了10个线程执行,10s后打印5个
            // 结论2:第1~5进来的任务由核心线程执行,第6~10将进入阻塞任务队列,第11~15个任务由临时线程执行
            // 核心线程或者临时线程空闲出来后去取阻塞任务队列里的任务执行
            for (int i = 0; i < 16; i++) {
                executor.submit(new Handle());
            }
            // 效果跟2的区别就是第16个任务进来将执行解决策略
        }
    
        public static class MyIgnorePolicy implements RejectedExecutionHandler {
    
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                System.err.println(r.toString() + " rejected");
            }
        }
    
    
        static class Handle implements Runnable {
    
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "--- executor...");
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    image-20200514150122488

红框里的10s后出现

跟例2的区别是:第16个任务进来的时候将执行拒绝策略

总结

小于或等于corePoolSize: 创建核心线程处理任务

大于corePoolSize且小于队列长度:进入阻塞队列

大于corePoolSize+队列长度,小于maxPoolSize+队列长度:创建临时线程处理任务

大于maxPoolSize+队列长度:执行拒绝策略

核心线程和临时线程无论谁空闲出来就去阻塞队列里取任务执行

配置

  • 高并发、任务执行时间短:线程数设置CPU核数+1(尽量少),目的是减少线程上下文切换
  • 高并发、任务执行时间长:
    1. 数据缓存
    2. 服务器集群
    3. 任务拆分,异步解耦
  • 并发低、任务执行时间长:
    1. 瓶颈在磁盘IO, 增加线程数,让CPU都动起来,可以设置CPU核数*2
    2. 业务计算密集(又叫CPU密集型),线程数设置的少些,减少线程上下文切换,配置CPU核数+1

最大可用的处理器数量

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
每一步脚印都要扎得深一点!
原文地址:https://www.cnblogs.com/bloodthirsty/p/12890112.html