多线程之多线程ThreadPoolExecutor

简介

线程是一个程序员一定会涉及到的一个概念,但是线程的创建和切换都是代价比较大的。所以,我们有没有一个好的方案能做到线程的复用呢?这就涉及到一个概念——线程池。合理的使用线程池能够带来3个很明显的好处:
    1.降低资源消耗:通过重用已经创建的线程来降低线程创建和销毁的消耗
    2.提高响应速度:任务到达时不需要等待线程创建就可以立即执行。
    3.提高线程的可管理性:线程池可以统一管理、分配、调优和监控。
    java的线程池支持主要通过ThreadPoolExecutor来实现,我们使用的ExecutorService的各种线程池策略都是基于ThreadPoolExecutor实现的,所以ThreadPoolExecutor十分重要。要弄明白各种线程池策略,必须先弄明白ThreadPoolExecutor。

ThreadPoolExecutor的构造方法

ThreadPoolExecutor有四大构造方法,搞懂参数最多那个,其它的也就理解,具体看APi,
这里只讨论:

ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) 

/**
 * ThreadPoolExecutor有四大构造方法
 * 重点看 七大构造参数的构造方法
 * int corePoolSize,(核心线程池大小,要保持在池中的线程数)
 * 
 * int maximumPoolSize,(线程池中允许的最大线程数)
 * 
 * long keepAliveTime,(线程池中超过corePoolSize数目的空闲线程最大存活时间)
 * 
 * TimeUnit unit,(时间单位)
 * 
 * BlockingQueue workQueue,(阻塞任务队列)
 * 
 * ThreadFactory threadFactory,(新建线程工厂)
 * 
 * RejectedExecutionHandler handler (当提交任务数超过maxmumPoolSize+workQueue之和时,任务会交给RejectedExecutionHandler来处理)
 * @throws IllegalArgumentException if one of the following holds:
* {@code corePoolSize < 0}
* {@code keepAliveTime < 0}
* {@code maximumPoolSize <= 0}
* {@code maximumPoolSize < corePoolSize} * @throws NullPointerException if {@code workQueue} * or {@code threadFactory} or {@code handler} is null */

想了解BlockingQueue workQueue:
想了解RejectedExecutionHandler handler:http://blog.csdn.net/Kincym/article/details/78318944


public class ThreadPoolExecutorTest {
    private static final CountDownLatch countDownLatch = new CountDownLatch(3);

    public static void main(String[] args) throws InterruptedException {

        ThreadPoolExecutor executorService = (ThreadPoolExecutor) buildPool();
//        countDownLatch.await();

        executorService.shutdown(); //任务执行完毕,关闭线程池。
        executorService.awaitTermination(1,TimeUnit.HOURS);//等待结束,最多等待1个小时,线程池shutdown.
        System.out.println("结束");
    }

    private static ExecutorService buildPool() {
        /**
         * 举例说明:何时启动最大线程数
         * corePoolSize为1,maximumPoolSize为2,workQueue.size()为1
         * I: 当启动2个线程时,corePoolSize启动一个,workQueue里面放一个,maximumPoolSize不启动
         * II: 当启动三个线程时,corePoolSize启动一个,workQueue里面放一个,这时阻塞队列已经满了
         *     这时maximumPoolSize启动了。
         */
        ExecutorService executorService = new ThreadPoolExecutor(1, 2, 30, TimeUnit.SECONDS, new ArrayBlockingQueue(1),
                r -> {
                    Thread t = new Thread(r);
                    return t;
                }, new ThreadPoolExecutor.AbortPolicy());

        System.out.println("线程池已创建");
        executorService.execute(() -> sleepSeconds(5));
        executorService.execute(() -> sleepSeconds(5));
        executorService.execute(() -> sleepSeconds(5));
        return executorService;
    }

    private static void sleepSeconds(int seconds) {
        try {
            TimeUnit.SECONDS.sleep(seconds);
            System.out.println("***" + Thread.currentThread().getName() + "***");
//            countDownLatch.countDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

shutdown():记得一定要关闭线程池。
awaitTermination(long timeout, TimeUnit unit):等待结束,最多等待指定时间。
注意shutdownNow():执行该方法,线程池的状态立刻变成STOP状态,并试图停止所有正在执行的线程,不再处理还在池队列中等待的任务,当然,它会返回那些未执行的任务。它试图终止线程的方法是通过调用Thread.interrupt()方法来实现的,如果线程中有sleep 、wait、Condition、定时锁等应用, interrupt()方法是会中断当前的线程(慎用).


在JDKAPI中,更推荐使用Executors工厂类创建线程,前往:http://blog.csdn.net/Kincym/article/details/78306354

你可能感兴趣的:(多线程)