版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
线程池详解(ThreadPoolExecutor)前言在实现异步时,基本都是使用线程池来实现,线程池在工作应用的还是比较频繁的,本文将就线程池的使用、相关原理和主要方法源码进行深入讲解学习。线程池的基本使用importjava.util.ArrayList;importjava.util.List;importjava.util.concurrent.Callable;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;importjava.util.concurrent.Future;importjava.util.concurrent.FutureTask;importjava.util.concurrent.LinkedBlockingQueue;importjava.util.concurrent.ScheduledExecutorService;importjava.util.concurrent.ThreadPoolExecutor;importjava.util.concurrent.TimeUnit;publicclassThreadPoolExecutorTest{/***创建一个线程池(完整入参):*核心线程数为5(corePoolSize),*最大线程数为10(maximumPoolSize),*存活时间为60分钟(keepAliveTime),*工作队列为LinkedBlockingQueue(workQueue),*线程工厂为默认的DefaultThreadFactory(threadFactory),*饱和策略(拒绝策略)为AbortPolicy:抛出异常(handler).*/privatestaticExecutorServiceTHREAD_POOL=newThreadPoolExecutor(5,10,60,TimeUnit.MINUTES,newLinkedBlockingQueue<Runnable>(),Executors.defaultThreadFactory(),newThreadPoolExecutor.AbortPolicy());/***只有一个线程的线程池没有超时时间,工作队列使用无界的LinkedBlockingQueue*/privatestaticExecutorServicesingleThreadExecutor=Executors.newSingleThreadExecutor();//privatestaticExecutorServicesingleThreadExecutor=Executors.newSingleThreadExecutor(Executors.defaultThreadFactory());/***有固定线程的线程池(即corePoolSize=maximumPoolSize)没有超时时间,*工作队列使用无界的LinkedBlockingQueue*/privatestaticExecutorServicefixedThreadPool=Executors.newFixedThreadPool(5);//privatestaticExecutorServicefixedThreadPool=Executors.newFixedThreadPool(5,Executors.defaultThreadFactory());/***大小不限的线程池核心线程数为0,最大线程数为Integer.MAX_VALUE,存活时间为60秒该线程池可以无限扩展,*并且当需求降低时会自动收缩,工作队列使用同步移交SynchronousQueue.*/privatestaticExecutorServicecachedThreadPool=Executors.newCachedThreadPool();//privatestaticExecutorServicecachedThreadPool=Executors.newCachedThreadPool(Executors.defaultThreadFactory());/***给定的延迟之后运行任务,或者定期执行任务的线程池*/privatestaticScheduledExecutorServicescheduledThreadPool=Executors.newScheduledThreadPool(5);//privatestaticScheduledExecutorServicescheduledThreadPool=Executors.newScheduledThreadPool(5,Executors.defaultThreadFactory());publicstaticvoidmain(Stringargs[])throwsException{/***例子1:没有返回结果的异步任务*/THREAD_POOL.submit(newRunnable(){@Overridepublicvoidrun(){//dosomethingSystem.out.println("没有返回结果的异步任务");}});/***例子2:有返回结果的异步任务*/Future<List<String>>future=THREAD_POOL.submit(newCallable<List<String>>(){@OverridepublicList<String>call(){List<String>result=newArrayList<>();result.add("JoonWhee");returnresult;}});List<String>result=future.get();//获取返回结果System.out.println("有返回结果的异步任务:"+result);/***例子3:*有延迟的,周期性执行异步任务*本例子为:延迟1秒,每2秒执行1次*/scheduledThreadPool.scheduleAtFixedRate(newRunnable(){@Overridepublicvoidrun(){System.out.println("thisis"+Thread.currentThread().getName());}},1,2,TimeUnit.SECONDS);/***例子4:FutureTask的使用*/Callable<String>task=newCallable<String>(){publicStringcall(){return"JoonWhee";}};FutureTask<String>futureTo=newFutureTask<String>(task);THREAD_POOL.submit(futureTo);System.out.println(futureTo.get());//获取返回结果//System.out.println(futureTo.get(3,TimeUnit.SECONDS));//超时时间为3秒}}线程池的定义和优点线程池,从字面含义来看,是指管理一组同构工作线程的资源池。线程池是与工作队列密切相关的,其中在工作队列中保存了所有等待执行的任务。工作者线程的任务很简单:从工作队列中获取一个任务,执行任务,然后返回线程池并等待下一个任务。“在线程池中执行任务“”比“为每个线程分配一个任务”优势更多。通过重用现有的线程而不是创建线程,可以在处理多个请求时分摊在线程创建和销毁过程中产生的巨大开销。另一个额外的好处是,当请求到达时,工作线程通常已经存在,因此不会由于等待创建线程而延迟任务的执行,从而提高了响应性。通过适当的调整线程池的大小,可以创建足够的线程以便使处理器保持忙碌状态,同时还可以防止过多线程相互竞争资源而使应用程序耗尽内存或失败。线程池的工作流程默认情况下,创建完线程池后并不会立即创建线程,而是等到有任务提交时才会创建线程来进行处理。(除非调用prestartCoreThread或prestartAllCoreThreads方法)
当线程数小于核心线程数时,每提交一个任务就创建一个线程来执行,即使当前有线程处于空闲状态,直到当前线程数达到核心线程数。
当前线程数达到核心线程数时,如果这个时候还提交任务,这些任务会被放到队列里,等到线程处理完了手头的任务后,会来队列中取任务处理。
当前线程数达到核心线程数并且队列也满了,如果这个时候还提交任务,则会继续创建线程来处理,直到线程数达到最大线程数。当前线程数达到最大线程数并且队列也满了,如果这个时候还提交任务,则会触发饱和策略。
如果某个线程的控线时间超过了keepAliveTime,那么将被标记为可回收的,并且当前线程池的当前大小超过了核心线程数时,这个线程将被终止。
工作队列如果新请求的到达速率超过了线程池的处理速率,那么新到来的请求将累积起来。在线程池中,这些请求会在一个由Executor管理的Runnable队列中等待,而不会像线程那样去竞争CPU资源。常见的工作队列有以下几种,前三种用的最多。ArrayBlockingQueue:列表形式的工作队列,必须要有初始队列大小,有界队列,先进先出。LinkedBlockingQueue:链表形式的工作队列,可以选择设置初始队列大小,有界/无界队列,先进先出。SynchronousQueue:SynchronousQueue不是一个真正的队列,而是一种在线程之间移交的机制。要将一个元素放入SynchronousQueue中,必须有另一个线程正在等待接受这个元素.如果没有线程等待,并且线程池的当前大小小于最大值,那么ThreadPoolExecutor将创建一个线程,否则根据饱和策略,这个任务将被拒绝。使用直接移交将更高效,因为任务会直接移交给执行它的线程,而不是被首先放在队列中,然后由工作者线程从队列中提取任务.只有当线程池是无解的或者可以拒绝任务时,SynchronousQueue才有实际价值.PriorityBlockingQueue:优先级队列,有界队列,根据优先级来安排任务,任务的优先级是通过自然顺序或Comparator(如果任务实现了Comparator)来定义的。
DelayedWorkQueue:延迟的工作队列,无界队列。
饱和策略(拒绝策略)当有界队列被填满后,饱和策略开始发挥作用。ThreadPoolExecutor的饱和策略可以通过调用setRejectedExecutionHandler来修改。(如果某个任务被提交到一个已被关闭的Executor时,也会用到饱和策略)。饱和策略有以下四种,一般使用默认的AbortPolicy。AbortPolicy:中止策略。默认的饱和策略,抛出未检查的RejectedExecutionException。调用者可以捕获这个异常,然后根据需求编写自己的处理代码。
DiscardPolicy:抛弃策略。当新提交的任务无法保存到队列中等待执行时,该策略会悄悄抛弃该任务。
DiscardOldestPolicy:抛弃最旧的策略。当新提交的任务无法保存到队列中等待执行时,则会抛弃下一个将被执行的任务,然后尝试重新提交新的任务。(如果工作队列是一个优先队列,那么“抛弃最旧的”策略将导致抛弃优先级最高的任务,因此最好不要将“抛弃最旧的”策略和优先级队列放在一起使用)。
CallerRunsPolicy:调用者运行策略。该策略实现了一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者(调用线程池执行任务的主线程),从而降低新任务的流程。它不会在线程池的某个线程中执行新提交的任务,而是在一个调用了execute的线程中执行该任务。当线程池的所有线程都被占用,并且工作队列被填满后,下一个任务会在调用execute时在主线程中执行(调用线程池执行任务的主线程)。由于执行任务需要一定时间,因此主线程至少在一段时间内不能提交任务,从而使得工作者线程有时间来处理完正在执行的任务。在这期间,主线程不会调用accept,因此到达的请求将被保存在TCP层的队列中。如果持续过载,那么TCP层将最终发现它的请求队列被填满,因此同样会开始抛弃请求。当服务器过载后,这种过载情况会逐渐向外蔓延开来——从线程池到工作队列到应用程序再到TCP层,最终达到客户端,导致服务器在高负载下实现一种平缓的性能降低。
线程工厂每当线程池需要创建一个线程时,都是通过线程工厂方法来完成的。在ThreadFactory中只定义了一个方法newThread,每当线程池需要创建一个新线程时都会调用这个方法。Executors提供的线程工厂有两种,一般使用默认的,当然如果有特殊需求,也可以自己定制。DefaultThreadFactory:默认线程工厂,创建一个新的、非守护的线程,并且不包含特殊的配置信息。PrivilegedThreadFactory:通过这种方式创建出来的线程,将与创建privilegedThreadFactory的线程拥有相同的访问权限、AccessControlContext、ContextClassLoader。如果不使用privilegedThreadFactory,线程池创建的线程将从在需要新线程时调用execute或submit的客户程序中继承访问权限。自定义线程工厂:可以自己实现ThreadFactory接口来定制自己的线程工厂方法。
ThreadPoolExecutor源码解析几个点了解这几个点,有助于你阅读下面的源码解释。下面的源码解读中提到的运行状态就是runState,有效的线程数就是workerCount,内容比较多,所以可能两种写法都用到。运行状态的一些定义:RUNNING:接受新任务并处理排队任务;SHUTDOWN:不接受新任务,但处理排队任务;STOP:不接受新任务,不处理排队任务,并中断正在进行的任务;TIDYING:所有任务已经终止,workerCount为零,线程转换到状态TIDYING将运行terminate()钩子方法;TERMINATED:terminated()已经完成,该方法执行完毕代表线程池已经完全终止。运行状态之间并不是随意转换的,大多数状态都只能由固定的状态转换而来,转换关系见第4点~第8点。RUNNING->SHUTDOWN:在调用shutdown()时,可能隐含在finalize()。(RUNNINGorSHUTDOWN)->STOP:调用shutdownNow()。SHUTDOWN->TIDYING:当队列和线程池都是空的时。
STOP->TIDYING:当线程池为空时。
TIDYING->TERMINATED:当terminate()方法完成时。
基础属性(很重要)/***主池控制状态ctl是包含两个概念字段的原子整数:workerCount:指有效的线程数量;*runState:指运行状态,运行,关闭等。为了将workerCount和runState用1个int来表示,*我们限制workerCount范围为(2^29)-1,即用int的低29位用来表示workerCount,*用int的高3位用来表示runState,这样workerCount和runState刚好用int可以完整表示。*///初始化时有效的线程数为0,此时ctl为:10100000000000000000000000000000privatefinalAtomicIntegerctl=newAtomicInteger(ctlOf(RUNNING,0));//高3位用来表示运行状态,此值用于运行状态向左移动的位数,即29位privatestaticfinalintCOUNT_BITS=Integer.SIZE-3;//线程数容量,低29位表示有效的线程数,00011111111111111111111111111111privatestaticfinalintCAPACITY=(1<<COUNT_BITS)-1;/***大小关系:RUNNING<SHUTDOWN<STOP<TIDYING<TERMINATED,*源码中频繁使用大小关系来作为条件判断。*10100000000000000000000000000000运行*01100000000000000000000000000000关闭*01100000000000000000000000000000停止*01100000000000000000000000000000整理*01100000000000000000000000000000终止*/privatestaticfinalintRUNNING=-1<<COUNT_BITS;//运行privatestaticfinalintSHUTDOWN=0<<COUNT_BITS;//关闭privatestaticfinalintSTOP=1<<COUNT_BITS;//停止privatestaticfinalintTIDYING=2<<COUNT_BITS;//整理privatestaticfinalintTERMINATED=3<<COUNT_BITS;//终止/***得到运行状态:入参c为ctl的值,~CAPACITY高3位为1低29位全为0,*因此运算结果为ctl的高3位,也就是运行状态*/privatestaticintrunStateOf(intc){returnc&~CAPACITY;}/***得到有效的线程数:入参c为ctl的值,CAPACITY高3为为0,*低29位全为1,因此运算结果为ctl的低29位,也就是有效的线程数*/privatestaticintworkerCountOf(intc){returnc&CAPACITY;}/***得到ctl的值:高3位的运行状态和低29位的有效线程数进行或运算,*组合成一个完成的32位数*/privatestaticintctlOf(intrs,intwc){returnrs|wc;}//状态c是否小于sprivatestaticbooleanrunStateLessThan(intc,ints){returnc<s;}//状态c是否大于等于sprivatestaticbooleanrunStateAtLeast(intc,ints){returnc>=s;}//状态c是否为RUNNING(小于SHUTDOWN的状态只有RUNNING)privatestaticbooleanisRunning(intc){returnc<SHUTDOWN;}//使用CAS增加一个有效的线程privatebooleancompareAndIncrementWorkerCount(intexpect){returnpareAndSet(expect,expect+1);}//使用CAS减少一个有效的线程privatebooleancompareAndDecrementWorkerCount(intexpect){returnpareAndSet(expect,expect-1);}//减少一个有效的线程privatevoiddecrementWorkerCount(){do{}while(!compareAndDecrementWorkerCount(ctl.get()));}//工作队列privatefinalBlockingQueue<Runnable>workQueue;//锁privatefinalReentrantLockmainLock=newReentrantLock();//包含线程池中的所有工作线程,只有在mainLock的情况下才能访问,Worker集合privatefinalHashSet<Worker>workers=newHashSet<Worker>();privatefinalConditiontermination=mainLock.newCondition();//跟踪线程池的最大到达大小,仅在mainLock下访问privateintlargestPoolSize;//总的完成的任务数privatelongcompletedTaskCount;//线程工厂,用于创建线程privatevolatileThreadFactorythreadFactory;//拒绝策略privatevolatileRejectedExecutionHandlerhandler;/***线程超时时间,当线程数超过corePoolSize时生效,*如果有线程空闲时间超过keepAliveTime,则会被终止*/privatevolatilelongkeepAliveTime;//是否允许核心线程超时,默认false,false情况下核心线程会一直存活。privatevolatilebooleanallowCoreThreadTimeOut;//核心线程数privatevolatileintcorePoolSize;//最大线程数privatevolatileintmaximumPoolSize;//默认饱和策略(拒绝策略),抛异常privatestaticfinalRejectedExecutionHandlerdefaultHandler=newAbortPolicy();privatestaticfinalRuntimePermissionshutdownPerm=newRuntimePermission("modifyThread");/***Worker类,每个Worker包含一个线程、一个初始任务、一个任务计算器*/privatefinalclassWorkerextendsAbstractQueuedSynchronizerimplementsRunnable{privatestaticfinallongserialVersionUID=6138294804551838833L;finalThreadthread;//Worker对应的线程RunnablefirstTask;//运行的初始任务。volatilelongcompletedTasks;//每个线程的任务计数器Worker(RunnablefirstTask){setState(-1);//禁止中断,直到runWorkerthis.firstTask=firstTask;//设置为初始任务//使用当前线程池的线程工厂创建一个线程this.thread=getThreadFactory().newThread(this);}//将主运行循环委托给外部runWorkerpublicvoidrun(){runWorker(this);}//Lockmethods////Thevalue0representstheunlockedstate.//Thevalue1representsthelockedstate./***通过AQS的同步状态来实现锁机制。state为0时代表锁未被获取(解锁状态),*state为1时代表锁已经被获取(加锁状态)。*/protectedbooleanisHeldExclusively(){//returngetState()!=0;}protectedbooleantryAcquire(intunused){//尝试获取锁if(compareAndSetState(0,1)){//使用CAS尝试将state设置为1,即尝试获取锁//成功将state设置为1,则当前线程拥有独占访问权setExclusiveOwnerThread(Thread.currentThread());returntrue;}returnfalse;}protectedbooleantryRelease(intunused){//尝试释放锁setExclusiveOwnerThread(null);//释放独占访问权:即将独占访问线程设为nullsetState(0);//解锁:将state设置为0returntrue;}publicvoidlock(){acquire(1);}//加锁publicbooleantryLock(){returntryAcquire(1);}//尝试加锁publicvoidunlock(){release(1);}//解锁publicbooleanisLocked(){returnisHeldExclusively();}//是否为加锁状态voidinterruptIfStarted(){//如果线程启动了,则进行中断Threadt;if(getState()>=0&&(t=thread)!=null&&!t.isInterrupted()){try{errupt();}catch(SecurityExceptionignore){}}}}execute方法使用线程池的submit方法提交任务时,会走到该方法,该方法也是线程池最重要的方法。
publicvoidexecute(Runnablecommand){if(command==null)//为空校验thrownewNullPointerException();intc=ctl.get();//拿到当前的ctl值if(workerCountOf(c)<corePoolSize){//如果有效的线程数小于核心线程数if(addWorker(command,true))//则新建一个线程来处理任务(核心线程)return;c=ctl.get();//拿到当前的ctl值}//走到这里说明有效的线程数已经>=核心线程数if(isRunning(c)&&workQueue.offer(command)){//如果当前状态是运行,尝试将任务放入工作队列intrecheck=ctl.get();//再次拿到当前的ctl值//如果再次检查状态不是运行,则将刚才添加到工作队列的任务移除if(!isRunning(recheck)&&remove(command))reject(command);//并调用拒绝策略elseif(workerCountOf(recheck)==0)//如果再次检查时,有效的线程数为0,addWorker(null,false);//则新建一个线程(非核心线程)}//走到这里说明工作队列已满elseif(!addWorker(command,false))//尝试新建一个线程来处理任务(非核心)reject(command);//如果失败则调用拒绝策略}该方法就是对应上文的线程池的工作流程。主要调用到的方法为addWorker(见下文addWorker方法解读)。
addWorker方法方法主要目的就是使用入参中的firstTask和当前线程添加一个Worker,前面的for循环主要是对当前线程池的运行状态和有效的线程数进行一些校验,校验逻辑比较绕,可以参考注释进行理解。该方法涉及到的其他方法有addWorkerFailed(见下文addWorkerFailed源码解读);还有就是Worker的线程启动时,会调用Worker里的run方法,执行runWorker(this)方法(见下文runWorker源码解读)。
addWorkerFailed方法/***Rollsbacktheworkerthreadcreation.*-removesworkerfromworkers,ifpresent*-decrementsworkercount*-rechecksfortermination,incasetheexistenceofthis*workerwasholdinguptermination*/privatevoidaddWorkerFailed(Workerw){//回滚Worker的添加,就是将Worker移除finalReentrantLockmainLock=this.mainLock;mainLock.lock();try{if(w!=null)workers.remove(w);//移除WorkerdecrementWorkerCount();//有效线程数-1tryTerminate();//有worker线程移除,可能是最后一个线程退出需要尝试终止线程池}finally{mainLock.unlock();}}该方法很简单,就是移除入参中的Worker并将workerCount-1,最后调用tryTerminate尝试终止线程池,tryTerminate见下文对应方法源码解读。runWorker方法上文addWork方法里说道,当Worker里的线程启动时,就会调用该方法。/***Worker的线程开始执行任务*/finalvoidrunWorker(Workerw){Threadwt=Thread.currentThread();//获取当前线程Runnabletask=w.firstTask;//拿到Worker的初始任务w.firstTask=null;w.unlock();//allowinterruptsbooleancompletedAbruptly=true;//Worker是不是因异常而死亡try{while(task!=null||(task=getTask())!=null){//Worker取任务执行w.lock();//加锁/**如果线程池停止,确保线程中断;如果不是,确保线程不被中断。*在第二种情况下进行重新检查,以便在清除中断的同时处理shutdownNow竞争*线程池停止指运行状态为STOP/TIDYING/TERMINATED中的一种*/if((runStateAtLeast(ctl.get(),STOP)||//判断线程池运行状态(Terrupted()&&//重新检查runStateAtLeast(ctl.get(),STOP)))&&//再次判断线程池运行状态!wt.isInterrupted())//走到这里代表线程池运行状态为停止,检查wt是否中断errupt();//线程池的状态为停止并且wt不为中断,则将wt中断try{beforeExecute(wt,task);//执行beforeExecute(默认空,需要自己重写)Throwablethrown=null;try{task.run();//执行任务}catch(RuntimeExceptionx){thrown=x;throwx;//如果抛异常,则completedAbruptly为true}catch(Errorx){thrown=x;throwx;}catch(Throwablex){thrown=x;thrownewError(x);}finally{afterExecute(task,thrown);//执行afterExecute(需要自己重写)}}finally{task=null;//将执行完的任务清空pletedTasks++;//Worker完成任务数+1w.unlock();}}completedAbruptly=false;//如果执行到这里,则worker是正常退出}finally{processWorkerExit(w,completedAbruptly);//调用processWorkerExit方法}}该方法为Worker线程开始执行任务,首先执行当初创建Worker时的初始任务,接着从工作队列中获取任务执行。主要涉及两个方法:获取任务的方法getTask(见下文getTask源码解读)和执行Worker退出的方法processWorkerExit(见下文processWorkerExit源码解读)。注:processWorkerExit在处理正常Worker退出时,没有对workerCount-1,而是在getTask方法中进行workerCount-1。
getTask方法privateRunnablegetTask(){//Worker从工作队列获取任务booleantimedOut=false;//poll方法取任务是否超时for(;;){//无线循环intc=ctl.get();//ctlintrs=runStateOf(c);//当前运行状态//如果线程池运行状态为停止,或者可以停止(状态为SHUTDOWN并且队列为空)//则返回null,代表当前Worker需要移除if(rs>=SHUTDOWN&&(rs>=STOP||workQueue.isEmpty())){decrementWorkerCount();//将workerCount-1//返回null前将workerCount-1,//因此processWorkerExit中completedAbruptly=false时无需再减returnnull;}intwc=workerCountOf(c);//当前的workerCount//判断当前Worker是否可以被移除,即当前Worker是否可以一直等待任务。//如果allowCoreThreadTimeOut为true,或者workerCount大于核心线程数,//则当前线程是有超时时间的(keepAliveTime),无法一直等待任务。booleantimed=allowCoreThreadTimeOut||wc>corePoolSize;//如果wc超过最大线程数或者当前线程会超时并且已经超时,//并且wc>1或者工作队列为空,则返回null,代表当前Worker需要移除if((wc>maximumPoolSize||(timed&&timedOut))&&(wc>1||workQueue.isEmpty())){//确保有Worker可以移除if(compareAndDecrementWorkerCount(c))//返回null前将workerCount-1,//因此processWorkerExit中completedAbruptly=false时无需再减returnnull;continue;}try{//根据线程是否会超时调用相应的方法,poll为带超时的获取任务方法//take()为不带超时的获取任务方法,会一直阻塞直到获取到任务Runnabler=timed?workQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS):workQueue.take();if(r!=null)returnr;timedOut=true;//走到这代表当前线程获取任务超时}catch(InterruptedExceptionretry){timedOut=false;//被中断}}}Worker从工作队列获取任务,如果allowCoreThreadTimeOut为false并且
workerCount<=corePoolSize,则这些核心线程永远存活,并且一直在尝试获取工作队列的任务;否则,线程会有超时时间(keepAliveTime),当在keepAliveTime时间内获取不到任务,该线程的Worker会被移除。
Worker移除的过程:getTask方法返回null,导致runWorker方法中跳出while循环,调用processWorkerExit方法将Worker移除。注意:在返回null的之前,已经将workerCount-1,因此在processWorkerExit中,completedAbruptly=false的情况(即正常超时退出)不需要再将workerCount-1。
processWorkerExit方法privatevoidprocessWorkerExit(Workerw,booleancompletedAbruptly){//Worker的退出//如果Worker是异常死亡(completedAbruptly=true),则workerCount-1;//如果completedAbruptly为false的时候(正常超时退出),则代表task=getTask()等于null,//getTask()方法中返回null的地方,都已经将workerCount-1,所以此处无需再-1if(completedAbruptly)decrementWorkerCount();finalReentrantLockmainLock=this.mainLock;mainLock.lock();//加锁try{completedTaskCount+=pletedTasks;//该Worker完成的任务数加到总完成的任务数workers.remove(w);//移除该Worker}finally{mainLock.unlock();}tryTerminate();//有Worker线程移除,可能是最后一个线程退出,需要尝试终止线程池intc=ctl.get();//获取当前的ctlif(runStateLessThan(c,STOP)){//如果线程池的运行状态还没停止(RUNNING或SHUTDOWN)if(!completedAbruptly){//如果Worker不是异常死亡//min为线程池的理论最小线程数:如果允许核心线程超时则min为0,否则min为核心线程数intmin=allowCoreThreadTimeOut?0:corePoolSize;//如果min为0,工作队列不为空,将min设置为1,确保至少有1个Worker来处理队列里的任务if(min==0&&!w
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年高中秋季开学节约粮食光盘行动德育教育
- 2027届江苏省南京市下关区三年级数学第一学期期末达标检测模拟试题含解析
- 2026届专业技能考试(机电+健康器材)测试卷及答案
- 宿州市2027届数学四年级第一学期期末综合测试试题含解析
- 2027届江西省萍乡市莲花县三年级数学第一学期期末监测试题含解析
- 2025-2026学年广西壮族自治区北海市高三一诊考试生物试卷含解析
- 2025-2026学年青岛市高考生物必刷试卷含解析
- 2026欧洲农产品精深加工技术效率研究报告
- 2026人工智能客服机器人开发与应用商业案例研究报告
- 2026中国涡流泵行业龙头企业战略布局案例研究
- 小红书种草营销师模拟题及答案
- 2025至2030中国工业磁控管行业市场深度研究与战略咨询分析报告
- 工程造价咨询企业服务清单
- 三方协议包车合同范本
- DB65∕T 4747-2024 地表水自压滴灌工程设计规范
- 光伏电站日常维护与运行规范
- 抗菌药物分级管理培训
- (正式版)DB65∕T 4450-2021 《农村供水工程自动化监控及信息化管理系统设计导则》
- 纸箱设计平面图制作规范
- 人教八年级英语上册Unit 7《Section A》课件
- 牙关紧闭抽搐的急救护理措施
评论
0/150
提交评论