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();

    }
原文地址:https://www.cnblogs.com/haiyangwu/p/10445584.html