• java自带的四种线程池


    java预定义的哪四种线程池?

    • newSingleThreadExexcutor:单线程数的线程池(核心线程数=最大线程数=1)
    • newFixedThreadPool:固定线程数的线程池(核心线程数=最大线程数=自定义)
    • newCacheThreadPool:可缓存的线程池(核心线程数=0,最大线程数=Integer.MAX_VALUE)
    • newScheduledThreadPool:支持定时或周期任务的线程池(核心线程数=自定义,最大线程数=Integer.MAX_VALUE)

    四种线程池有什么区别?

    上面四种线程池类都继承ThreadPoolExecutor,在创建时都是直接返回new ThreadPoolExecutor(参数),它们的区别是定义的ThreadPoolExecutor(参数)中参数不同,而ThreadPoolExecutor又继承ExecutorService接口类

    • newFixedThreadPool
    定义:
    ExecutorService executorService=Executors.newFixedThreadPool(2);
    

    image

    缺点:使用了LinkBlockQueue的链表型阻塞队列,当任务的堆积速度大于处理速度时,容易堆积任务而导致OOM内存溢出

    • newSingleThreadExecutor
    定义:ExecutorService executorService =Executors.newSingleThreadExecutor();
    

    image

    上面代码神似new FixedThreadPoop(1),但又有区别,因为外面多了一层FinalizableDelegatedExecutorService,其作用:
    image

    可知,fixedExecutorService的本质是ThreadPoolExecutor,所以fixedExecutorService可以强转成ThreadPoolExecutor,但singleExecutorService与ThreadPoolExecutor无任何关系,所以强转失败,故newSingleThreadExecutor()被创建后,无法再修改其线程池参数,真正地做到single单个线程。

    缺点:使用了LinkBlockQueue的链表型阻塞队列,当任务的堆积速度大于处理速度时,容易堆积任务而导致OOM内存溢出

    • newCacheThreadPool
    定义:ExecutorService executorService=Executors.newCacheThreadPool();
    

    image

    缺点:SynchronousQueue是BlockingQueue的一种实现,它也是一个队列,因为最大线程数为Integer.MAX_VALUE,所有当线程过多时容易OOM内存溢出

    • ScheduledThreadPool
    定义:ExecutorService executorService=Executors.newScheduledThreadPool(2);
    
    源码:
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
            //ScheduledThreadPoolExecutor继承ThreadPoolExecutor
            return new ScheduledThreadPoolExecutor(corePoolSize);
        }
        
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        //ScheduledThreadPoolExecutor继承ThreadPoolExecutor,故super()会调用ThreadPoolExecutor的构造函数初始化并返回一个ThreadPoolExecutor,而ThreadPoolExecutor使实现ExecutorService接口的
        //最终ScheduledThreadPoolExecutor也和上面几种线程池一样返回的是ExecutorService接口的实现类ThreadPoolExecutor
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }
    

    线程池有哪几个重要参数?

    ThreadPoolExecutor构造方法如下:

    image

    image

    • keepAliveTime是指当前线程数位于 [核心线程数,最大线程数] 之间的这些非核心线程等待多久空闲时间而没有活干时,就退出线程池;
    • 等待丢列的大小与最大线程数是没有任何关系的,线程创建优先级=核心线程 > 阻塞队列 > 扩容的线程(当前核心线程数小于最大线程数时才能扩容线程)
    • 假如核心线程数5,等待队列长度为3,最大线程数10:当线程数不断在增加时,先创建5个核心线程,核心线程数满了再把线程丢进等待丢列,等待队列满了(3个线程),此时会比较最大线程数(只有等待丢列满了最大线程数才能出场),还可以继续创建2个线程(5+3+2),若线程数超过了最大线程数,则执行拒绝策略;
    • 假如核心线程数5,等待队列长度为3,最大线程数7:当线程数不断在增加时,先创建5个核心线程,核心线程数满了再把线程丢进等待丢列,当等待队列中有2个线程时达到了最大线程数(5+2=7),但是等待丢列还没满所以不用管最大线程数,直到等待丢列满了(3个阻塞线程),此时会比较最大线程数(只有等待丢列满了最大线程数才能出场),此时核心+等待丢列=5+3=8>7=最大线程数,即已经达到最大线程数了,则执行拒绝策略;
    • 如果把等待丢列设置为LinkedBlockingQueue无界丢列,这个丢列是无限大的,就永远不会走到判断最大线程数那一步了

    如何自定义线程池

    可以使用有界队列,自定义线程创建工厂ThreadFactory和拒绝策略handler来自定义线程池

    public class ThreadTest {
        public static void main(String[] args) throws InterruptedException, IOException {
            int corePoolSize = 2;
            int maximumPoolSize = 4;
            long keepAliveTime = 10;
            TimeUnit unit = TimeUnit.SECONDS;
            BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(2);
            ThreadFactory threadFactory = new NameTreadFactory();
            RejectedExecutionHandler handler = new MyIgnorePolicy();
           ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit,
                    workQueue, threadFactory, handler);
            executor.prestartAllCoreThreads(); // 预启动所有核心线程        
            for (int i = 1; i <= 10; i++) {
                MyTask task = new MyTask(String.valueOf(i));
                executor.execute(task);
            }
            System.in.read(); //阻塞主线程
        }
        static class NameTreadFactory implements ThreadFactory {
            private final AtomicInteger mThreadNum = new AtomicInteger(1);
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r, "my-thread-" + mThreadNum.getAndIncrement());
                System.out.println(t.getName() + " has been created");
                return t;
            }
        }
    
        public static class MyIgnorePolicy implements RejectedExecutionHandler {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
                doLog(r, e);
            }
            private void doLog(Runnable r, ThreadPoolExecutor e) {
                // 可做日志记录等
                System.err.println( r.toString() + " rejected");
    //          System.out.println("completedTaskCount: " + e.getCompletedTaskCount());
            }
        }
    
        static class MyTask implements Runnable {
            private String name;
            public MyTask(String name) {
                this.name = name;
            }
            @Override
            public void run() {
                try {
                    System.out.println(this.toString() + " is running!");
                    Thread.sleep(3000); //让任务执行慢点
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            public String getName() {
                return name;
            }
            @Override
            public String toString() {
                return "MyTask [name=" + name + "]";
            }
        }
    }
    

    运行结果:

    image

    其中7-10号线程被拒绝策略拒绝了,1、2号线程执行完后,3、6号线程进入核心线程池执行,此时4、5号线程在任务队列等待执行,3、6线程执行完再通知4、5线程执行

  • 相关阅读:
    某邮储银行数据归集系统在HTAP场景下的选型与实践
    洛谷P2196 [NOIP1996 提高组] 挖地雷【动态规划思路分析】看完直接举一反三!
    python基础环境
    Linux安装maven
    BERT预训练模型学习笔记
    【无标题】
    typescript45-接口之间的兼容性
    FPGA-时钟管理单元
    盘点5个C#实用的Word、PPT、Excel、Mail第三方库
    用MinIO搭建对象存储服务
  • 原文地址:https://www.cnblogs.com/mofes/p/16190858.html