当前位置: 首页 > 后端技术 > Java

5种判断线程池是否完全完成的方法,还有谁不会?

时间:2023-04-01 18:52:55 Java

来源:https://blog.csdn.net/m0_4614...概述最近在写小玩具的时候用到了CountDownLatch计数器,然后想了想有多少种判断线程池结束的方法。我在网上搜了一下,可能没有找到,但是我找到了(所有方法都在ThreadPoolExecutor线程池方法下测试):isTerminated()判断方法,执行shutdown()后,关闭线程池后,判断是否所有任务都已完成。ThreadPoolExecutor的getCompletedTaskCount()方法判断完成的任务数是否等于所有任务数。CountDownLatch计数器,使用latch计数判断是否全部完成。手动维护公共计数在原理上类似于锁定,但更灵活。使用submit提交任务到线程池,Future判断任务执行状态。好了,现在就来一一介绍优缺点和简要原理;先创建一个静态线程池,后面的例子我们就不一一创建了,都用这个:/***创建一个最大线程数为20的线程线程池*/publicstaticThreadPoolExecutorpool=newThreadPoolExecutor(10,20,0L,TimeUnit.MILLISECONDS,newLinkedBlockingQueue<>());然后准备一个通用的sleep方法:/***线程执行方法,随机等待0到10秒*/privatestaticvoidsleepMtehod(intindex){try{longsleepTime=newDouble(Math.random()*10000).长值();Thread.sleep(sleepTime);System.out.println("当前线程执行结束:"+index);}catch(InterruptedExceptione){e.printStackTrace();}}这个方法是为了在测试的时候区分线程的执行顺序。好了,准备好了,让我们现在开始吧。isTerminated方法先贴测试代码:privatestaticvoidshutdownTest()throwsException{for(inti=0;i<30;i++){intindex=i;pool.execute(()->sleepMtehod(index));}pool.shutdown();while(!pool.isTerminated()){Thread.sleep(1000);System.out.println("还没有结束...");}System.out.println("Allexecutioncompleted");}这个方法是在主线程中循环判断是否所有任务都执行完毕,这里主要有两个方法:shutdown():以Orderly启动shutdown,之前提交的任务会被执行,但是不会接受新的任务。如果已经关闭,调用没有额外的效果先执行shutdown或者shutdownNow,通俗点说就是所有任务都执行完之后,依次对线程池执行shutdown(),然后循环isTerminated()判断线程池是否完全执行完毕。:操作简单,代码更简单缺点:需要关闭线程池,一般我在代码中将线程池注入到Spring容器中,然后在每个组件中使用同一个,当然不能关闭。类似的方法扩展:shutdownNow():try停止所有主动执行的任务,停止等待任务的处理,并返回等待执行的任务列表。从此方法返回时,这些任务将从任务队列中删除。通过Thread.interrupt()取消任务。isShutdown():如果线程池关闭则返回true。isTerminating():如果在shutdown()或shutdownNow()之后终止但尚未完全终止,则返回true。waitTermination(longtimeout,TimeUnitunit):当前线程阻塞,直到所有Submitted任务(包括正在运行和在队列中等待)执行完,或者超时时间到,或者线程被中断抛出异常;所有执行返回true,超时返回false。也可以用这个方法代替isTerminated()来判断。getCompletedTaskCount还是一样,贴代码:privatestaticvoidtaskCountTest()throwsException{for(inti=0;i<30;i++){intindex=i;pool.execute(()->sleepMtehod(index));}//当线程池完成的线程数等于线程池中线程总数时while(!(pool.getTaskCount()==pool.getCompletedTaskCount())){System.out.println("任务总数:"+pool.getTaskCount()+";完成任务数:"+pool.getCompletedTaskCount());线程.睡眠(1000);System.out.println("还没停...");}System.out.println("全部执行完毕");}还是和主线程循环判断一样,主要有两个方法:getTaskCount():返回计划执行的任务总数。由于任务和线程的状态在计算过程中可能会动态变化,因此返回值只是一个近似值。getCompletedTaskCount():返回已完成执行的任务的大概总数。因为任务和线程的状态可能在计算过程中动态变化,所以返回值只是一个近似值,不会在连续调用之间减少。这很容易理解。任务总数等于已完成任务数,即所有任务都执行完毕。优点:充分利用了ThreadPoolExecutor提供的方法,不需要关闭线程池,避免了创建和销毁带来的损失。缺点:从上面的解释可以看出,使用这个判断有很大的限制;必须保证在循环判断过程中不产生新的任务。几乎意味着这个线程池只能在这个线程中使用。其他:最后两句,因为我用的是main方法运行,运行完main并没有结束,因为如果非守护线程不终止,程序就不会结束。但是在线程池Worker线程中写了一个死循环,并且设置为非守护线程。CountDownLatch计数器的方法是我常用的方法。先看代码:privatestaticvoidcountDownLatchTest()throwsException{//计数器,判断线程执行是否结束CountDownLatchtaskLatch=newCountDownLatch(30);对于(inti=0;i<30;i++){intindex=i;pool.execute(()->{sleepMtehod(index);taskLatch.countDown();System.out.println("当前计数器编号:"+taskLatch.getCount());});}//当前线程阻塞,等待计数器置0taskLatch.await();System.out.println("全部执行完毕");}这个方法,呃,看起来应该比较高级,不知道其他大佬是怎么写的,反正我就用这个。该方法需要引入工具类CountDownLatch。先写下这个方法的优缺点,后面再详细介绍这个类。优点:代码优雅,无需操作线程池,线程池作为Bean有很好的使用场景。缺点:需要提前知道线程数;性能确实,呃呃呃呃呃差了点。哦,对了,在线程代码块中也需要加入异常判断,否则在countDown之前出现异常,没有处理,会导致主线程永远阻塞在await中。CountDownLatch概述CountDownLatch是JDK提供的一种同步工具,它允许一个或多个线程等待,直到一组操作在其他线程中完成。常用的方法包括countDown方法和await方法。CountDownLatch初始化时,需要指定一个给定的整数作为计数器。当countDown方法被调用时,计数器会减1;当调用await方法时,如果计数器大于0,则线程将被阻塞,直到通过countDown方法将计数器减为0,线程才会继续执行。计数器无法重置。当计数器减为0时,调用await方法会直接返回。维护一个共同计数的方式其实和CountDownLatch的原理类似。先维护一个静态变量privatestaticinttaskNum=0;然后在线程任务结束时进行静态变量操作:privatestaticvoidstaticCountTest()throwsException{Locklock=newReentrantLock();对于(inti=0;i<30;i++){intindex=i;pool.execute(()->{sleepMtehod(index);lock.lock();taskNum++;lock.unlock();});}while(taskNum<30){Thread.sleep(1000);System.out.println("还没停止...当前完成的任务数:"+taskNum);}System.out.println("全部执行完毕");}其实就是加锁计数,循环判断。优点:手动维护方式比较灵活,对于一些特殊场景可以手动处理。缺点:与CountDownLatch相比,还需要知道线程数,但代码实现比较麻烦。与灵活性的优势相比,似乎投入与产出并不对等。FutureJudgmentTaskExecutionStatusFuture是用来加载线程结果的,但是用这个来判断和写代码总感觉怪怪的。因为Future只能加载一个线程的返回结果,多个线程不能使用List接收Future。这里有一个线程来演示:privatestaticvoidfutureTest()throwsException{Futurefuture=pool.submit(()->sleepMtehod(1));while(!future.isDone()){线程。睡眠(500);System.out.println("还没停...");}System.out.println("全部执行完毕");}这个方法优缺点就不写了,因为主要使用场景不是用来判断任务执行状态的。近期热点文章推荐:1.1000+Java面试题及答案(2022最新版)2.厉害了!Java协程来了。..3.SpringBoot2.x教程,太全面了!4.不要用爆破爆满画面,试试装饰者模式,这才是优雅的方式!!5.《Java开发手册(嵩山版)》最新发布,赶快下载吧!感觉不错,别忘了点赞+转发!