线程池ThreadPoolExecutor的使用

版权声明:欢迎转载大宇的博客,转载请注明出处: https://blog.csdn.net/yanluandai1985/article/details/82423767

一、手动创建线程的缺点:

        (1)创建多个线程,会消耗许多内存。
        (2)创建多个线程,也非常耗时。
        (3)最重要的是,频繁创建线程,在任务执行完毕之后被回收,对GC也有一定的压力。

二、线程池

        线程池:创建线程变成了从线程池获取空闲的线程,关闭线程变成了向池子中归还线程。
        合理地使用线程池能够带来三个好处:

        (1)降低内存资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

        (2)提高响应速度。在线程池中的线程都是已经被创建好的,我们的任务直接获取一个空闲的线程就能够被执行了。

        (3)提高线程的可管理性。使用线程池可以进行统一分配、调优和监控。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性。

三、线程池的代码

        JDK提供的线程池的继承结构。

        

       常用的是ThreadPollExecutor,看这个名字就知道采用的命令设计模式。

       采用多态可以向上转型为它的接口形式ExecutorService

       ThreadPoolExecutor execute(Runnable)方法 与父类ExecutorServicesubmit方法的区别

       execute(..) 方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功。

       submit(..) 方法用于提交需要返回值的任务。线程池会返回一个 future 类型的对象,通过这个 future 对象可以判断任务是否执行成功,并且可以通过 future 的 get() 方法来获取返回值,get() 方法会阻塞当前线程直到任务完成,而使用 get(long timeout,TimeUnit unit)方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完。

enter image description here

        示例代码

import java.util.concurrent.*;

/**
 * Created by jay.zhou on 2018/9/5.
 */
public class aas {
    public static void main(String[] args) {
        //创建一个线程池对象
        /**
         * 参数信息:
         * int corePoolSize     核心线程大小
         * int maximumPoolSize  线程池最大容量大小
         * long keepAliveTime   线程空闲时,线程存活的时间
         * TimeUnit unit        时间单位
         * BlockingQueue<Runnable> workQueue  任务队列。一个阻塞队列
         */
        ThreadPoolExecutor pool = new ThreadPoolExecutor(4, 4, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>(10));
        //另外一种写法,与上述本质为一致:
        //ExecutorService pool = Executors.newFixedThreadPool(4);

        //执行任务
        for (int i = 0; i < 10; i++) {
            int index = i;
            pool.execute( ()-> System.out.println("i:"+index+"execute!"));
        }
        //关闭线程池
        pool.shutdown();
    }
}

四、获取异常信息

       因为ExecutorService的submit()方法会在内部处理异常。所以,我们希望的是能够获取到这个异常信息。

       (1)第一种就是可以使用Future future = pool.submit();  再通过 future.get()方法获取其执行情况。

       

ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 2, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>(10));

        //执行任务
        Future future = pool.submit(() -> System.out.println(2 / 0));
        try {
            //查看执行情况,有异常将会在此显示。
            future.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        /**
         * java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
         * caused by java.lang.ArithmeticException
         */

        //将任务换成这个将会无任何打印信息
        //pool.submit(() -> System.out.println(2 / 0));

      (2) 第二种办法就是 向下转型为ThreadPoolExecutor,指定execute方法。

猜你喜欢

转载自blog.csdn.net/yanluandai1985/article/details/82423767