• java线程池


    线程池篇

    建议使用ThreadPoolExecutor类进行线程池的创建,更加细粒度的管理自己所使用的线程池,对线程池的分配也根据自己的实际情况来具体的控制

    如果使用线程池可能会导致OOM(outofMemoryError)

    核数的获取

    获取当前电脑的核数:Runtime.getRuntime().availableProcessors();

    ThreadPoolExecutor

    线程池最底层的类ThreadPoolExecutor

    ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
        2,
        /*
         *   IO 密集型 CPU*2
         *   CPU密集型 CPU核数+1 (逻辑处理器+1)
         * */
        5,
        60L,
        TimeUnit.SECONDS,
        //默认是Integer.Max_Value
        new LinkedBlockingQueue<Runnable>(3),
        Executors.defaultThreadFactory(),
        /**
         * abort RejectedExecutionException
         * CallerRunsPolicy 会回退到上一个线程,比如main线程
         * DiscardPolicy 放心新来的
         * DiscardOldestPolicy 放弃阻塞队列中最开始的那个
         */
        new ThreadPoolExecutor.DiscardOldestPolicy());
    

    Executors工具类

    newWorkStealingPool(1.8)

    public static ExecutorService newWorkStealingPool(int parallelism) {
        return new ForkJoinPool
            (parallelism,
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }
    
    public ForkJoinPool(int parallelism,
                        ForkJoinWorkerThreadFactory factory,
                        UncaughtExceptionHandler handler,
                        boolean asyncMode) {
        this(checkParallelism(parallelism),
             checkFactory(factory),
             handler,
             asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
             "ForkJoinPool-" + nextPoolId() + "-worker-");
        checkPermission();
    }
    
    private ForkJoinPool(int parallelism,
                         ForkJoinWorkerThreadFactory factory,
                         UncaughtExceptionHandler handler,
                         int mode,
                         String workerNamePrefix) {
        this.workerNamePrefix = workerNamePrefix;
        this.factory = factory;
        this.ueh = handler;
        this.config = (parallelism & SMASK) | mode;
        long np = (long)(-parallelism); // offset ctl counts
        this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);
    }
    //分支合并线程池
    

    newFixedThreadPool

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
    
    • 创建固定的线程数,创建的初始值和最大值都是一个
    • 创建的阻塞队列无上限

    newCachedThreadPool

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
    
    • 带缓存的线程池数,当开始的时候是0,最大是Integer.MAX_VALUE
    • 最长六十秒不被使用则被回收

    newSingleThreadPool

    public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1));
    }
    
    • 创建一个单个的线程池(里面只有一个)

    newScheduledThreadPool

    public static ScheduledExecutorService newScheduledThreadPool(
        int corePoolSize, ThreadFactory threadFactory) {
        return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
    }
    
    public ScheduledThreadPoolExecutor(int corePoolSize,
                                       ThreadFactory threadFactory) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue(), threadFactory);
    }
    
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }
    
    • 创建一个带时间的线程池,使用的是DelayedWorkQueue拒绝阻塞队列

    线程池的使用

    • execute():void
    • submit():Future

    对无返回值的线程执行

    try {
        for (int i = 0; i < 9; i++) {
            poolExecutor.execute(() -> {
                System.out.println(Thread.currentThread().getName() + "	");
            });
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        poolExecutor.shutdown();
    }
    

    对有返回值的线程执行

    poolExecutor.submit(new FutureTask<>(() -> 1024)).get();
    

    线程池的执行流程

    1. 首先来的线程任务开始开启小于等于corePoolSize的线程进行执行
    2. 如果有些线程还是没执行完,但是有新的任务来了,那么将会进入阻塞队列
    3. 如果阻塞队列满了,就会去开启新的线程来执行任务,线程<=MaxiNumPoolSize
    4. 当大于corePoolSize的线程在KeepAliveTime内没被使用则会被释放
    5. 如果开启了最大的线程还是有任务没有被执行,则会进行使用拒绝策略进行对新任务的拒绝

    线程池具体参数的配置*

    线程池的拒绝策略

    当等待队列满了&线程池的最大线程数也达到了,当出现新的任务时,会执行拒绝策略

    new ThreadPoolExecutor.CallerRunsPolicy()
    
    • abortPolicy 抛出RejectedExecutionException,阻止系统正常运行
    • CallerRunsPolicy 会回退到上一个线程(调用它的线程),比如main线程
    • DiscardPolicy 放弃新来的task,如果允许任务丢失,则是最好的一种策略
    • DiscardOldestPolicy 放弃阻塞队列中最开始的那个

    上述策略皆实现了RejectedExecutionHandler接口

    线程池最大线程数的设定

    CPU密集型

    • CPU核数+1个线程的线程池

    IO密集型

    • IO密集型任务线程并不是一直在执行任务,则应尽可能多的线程,CUP核数*2
    • CUP核数 / 1-阻塞系数 (阻塞系数在0.8~0.9之间)
      • 比如8核CPU: 4/1-0.9 = 40
  • 相关阅读:
    浅谈 iOS 之 Crash log 符号化
    聊聊 Statsd 和 Collectd 那点事!
    如何使用 Zend Expressive 建立 NASA 图片库?
    Nagios 邮箱告警的方式太OUT了!
    如何从软硬件层面提升 Android 动画性能?
    这样查看告警邮件要慢一点……
    Android 共享文件的 Runtime 权限
    第38节:hashCode()与toString()与equals()函数的作用,内部类和匿名内部类
    第37节:多线程安全问题
    第37节:多线程安全问题
  • 原文地址:https://www.cnblogs.com/lovestart/p/12464473.html
Copyright © 2020-2023  润新知