设为首页 加入收藏

TOP

Java并发之线程池的使用浅析
2019-08-13 05:36:26 】 浏览:32
Tags:Java 并发 线程 池的 使用 浅析

   当系统并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要消耗大量的系统资源。


线程池有两个重要的操作,提交任务和关闭线程池。在讲述这两个操作之前先了解一下线程池的状态。注意!!!,线程池的状态而不是线程状态。


在ThreadPoolExecutor中定义了一个volatile变量,另外定义了几个static final变量表示线程池的各个状态:


ThreadPoolExecutor的提交操作可以使用submit和execute这两种方法


 最核心的任务提交方法是execute()方法,虽然通过submit也可以提交任务,但是实际上submit方法里面最终调用的还是execute()方法 并且ExecutorService中的invokeAll(),invokeAny()都是调用的execute方法。execute提交的任务无返回值,因此无法判断任务是否执行成功。但是如果出现线程错误可以显示部分异常堆栈信息


详细流程解读


      如果使用submit 方法来提交任务,它会返回一个future,那么我们可以通过这个future来判断任务是否执行成功,通过future的get方法来获取返回值,get方法会阻塞住直到任务完成,而使用get(long timeout, TimeUnit unit)方法则会阻塞一段时间后立即返回,这时有可能任务没有执行完。可以通过以下方式改造submit获得部分异常堆栈信息


使用线程池时,我们可以通过调用线程池的shutdown或shutdownNow方法来关闭线程池,但是它们的实现原理不同。


只要调用了这两个关闭方法的其中一个,isShutdown方法就会返回true。当所有的任务都已关闭后,才表示线程池关闭成功,这时调用isTerminaed方法会返回true。至于我们应该调用哪一种方法来关闭线程池,应该由提交到线程池的任务特性决定,通常调用shutdown来关闭线程池,如果任务不一定要执行完,则可以调用shutdownNow。


常见的五种线程池


这里思考一个问题为什么newFixedThreadPool的corePoolSizemamximumPoolSize设计为一样的?


       答案可以从execute的源码中找到,首先线程池提交任务时是先判断corePoolSize,再判断workQueue,最后判断mamximumPoolSize,然而LinkedBlockingQueue是无界队列,所以它是达不到判断mamximumPoolSize这一步的,所以mamximumPoolSize成多少,并没有多大所谓。


下边简单的介绍一下newFixedThreadPool的使用


      这里创建了固定大小为5的线程,然后依次向线程池提交了10个任务。此后线程池就会安排调度这10个任务。每个任务都会将自己的执行时间和执行任务线程的Id打印出来,并且每一个任务执行时间为1秒


执行代码,输出如下



       可以看出,前5个任务和后5个任务执行时间相差1秒,并且前五个和后五个ID是一致的。这说明任务是分两个批次执行。这也符合一个只有5个线程的线程池行为


       该方法返回一个可根据实际情况调整线程数量大小的线程池,线程池的数量不确定,但若有空闲线程可以复用,则会优先使用可复用的线程,如果所有线程均在工作,又有新的任务被提交,


则会创建新的线程执行任务。所有线程在当前任务执行完毕后,将返回线程池进行复用。


        这里可以看到CachedThreadExecutormamximumPoolSize被设计成接近无限大。     


】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Java八大排序算法之冒泡排序 下一篇Java并发之阻塞队列浅析

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目