• Java 线程池


    一、使用线程池的优点:

      1、线程重用,避免线程创建的开销

      2、任务过多时,通过队列避免创建过多线程,减少系统资源消耗和竞争,确保任务有序完成

    二、如何使用线程池:

    1、ThreadPoolExecutor 构造方法:

    public class ThreadPoolExecutorTest {
    
        public static void main(String[] args){
    
    
            int num = 10;
            ArrayBlockingQueue<Runnable> arrayBlockingQueue = new ArrayBlockingQueue<>(num);
    
            RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.AbortPolicy();
    
            ThreadFactory threadFactory = new MyThreadFactory();
    
            /**
             * corePoolSize:核心线程个数
             * maximumPoolSize:最大线程个数
             * keepAliveTime、unit:空闲线程存活时间
             * workQueue:指定工作队列,要求是阻塞队列
             *   常用的阻塞队列类型:
             *      LinkedBlockingQueue:基于链表的阻塞队列,可以指定最大长度,但默认是无界的
             *      ArrayBlockingQueue:基于数组的有界阻塞队列
             *      PriorityBlockingQueue:基于堆的无界阻塞优先级队列
             *      SynchronousQueue:没有实际存储空间的同步阻塞队列
             */
            ThreadPoolExecutor threadPoolExecutor  = new ThreadPoolExecutor(3, 10, 10, TimeUnit.SECONDS, arrayBlockingQueue, threadFactory, rejectedExecutionHandler );
        }
    
        static class MyThreadFactory 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;
    
            MyThreadFactory() {
                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;
            }
        }
    } 

    2、任务拒绝策略:如果队列有界,且maximumPoolSize有限,则当队列排满,线程个数也达到了maximumPoolSize,这时,新任务来了,会触发线程池的任务拒绝策略。

    默认情况下,提交任务的方法(execute / submit / invokeAll)会抛RejectedExecutionException 异常。

    3、RejectedExecutionHandler 自定义拒绝策略的四种方式:

      1)ThreadPoolExecutor.AbortPolicy 默认的方式,抛出异常;

      2)ThreadPoolExecutor.DiscardPolicy 静默处理,忽略新任务,不跑处异常,也不执行;

      3)ThreadPoolExecutor.DiscardOldestPolicy 将等待时间最长的任务扔掉,然后自己排队;

      4)ThreadPoolExecutor.CallerRunsPoliy 在任务提交者线程中执行任务,而不是交给线程池中的线程执行;

    4、ThreadFactory 线程工厂:

      1)ThreadPoolExecutor的默认实现是Executors类中的静态内部类DefaultThreadFactory,主要就是创建一个线程,给线程设置一个名称,设置daemon为false,设置线程优先级为标准默认优先级,以及线程名称。

      源码如下:     

     /**
         * The default thread factory
         */
        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;
            }
        }

    5、关于核心线程的特殊配置:核心线程不会预先创建,只有当有任务时才会创建,核心线程不会因为空闲而被终止,keepAliveTime参数不适应于它。

    三、Executors 工厂类:

    Executors 提供了一些静态工厂方法,可以方便地创建一些预配置的线程池,主要方法有:

    1、newSingleThreadExecutor()  只使用一个线程,使用无界队列LinkedBlockingQueue,线程创建后不会超时终止,该线程顺序执行所有任务。该线程适用于需要确保所有任务被顺序执行的场合;

    2、newFixedThreadPool(int nThread) 使用固定数目的n个线程,使用无界队列LinkedBlockingQueue,线程创建后不会超时终止。和newSingleThreadExecutor一样,由于是无界队列,如果排队任务过多,可能会消耗过多的内存;

    3、newCachedThreadPool() 它的corePoolSize 为0,maximumPoolSize 为Integer.MAX_VALUE,keepAliveTime 是60秒,队列为SynchronousQueue。当新任务到来时,如果正好有空闲线程在等待任务,则其中一个空闲线程接受该任务,否则就总是创建一个新线程,创建的总线程个数不受限制,对任一空线程,如果60秒内没有新任务,就终止。

    代码实例:

     public static void executorsDemo(){
    
            ExecutorService executorService =  Executors.newSingleThreadExecutor();
    
            executorService = Executors.newFixedThreadPool(10);
    
            executorService = Executors.newCachedThreadPool();
    
    
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("Executors 工具类");
                }
            });
    
            executorService.shutdown();
    
        }
  • 相关阅读:
    SQliteDatabase详解
    Eclipse常用快捷键
    Android 省市区三级联动
    关于安卓9patch图片的探究
    9patch
    Day3_UI布局--FXQ
    day2-UI布局
    Day01_扩展_Genymotion模拟器的使用
    React Examples
    React项目结构
  • 原文地址:https://www.cnblogs.com/haiyangwu/p/10445584.html
Copyright © 2020-2023  润新知