ThreadPoolExecutor源码1

参考:https://www.cnblogs.com/liuyun1995/p/9305273.html

ThreadPoolExecutor1 executorService1 = new ThreadPoolExecutor1(3)

线程池的线程是懒初始化的,第一个任务来了创建一下执行,执行完了等待队列,只会从队列拿任务,不会直接接受任务。第二个任务来了,不会加到队列,也不会给第一个线程去执行,而是创建一个线程执行,第二个线程执行完了等待队列。第三个任务来了,即使前面2个线程执行完了,也不会给前面2个线程执行,而是创建第三个线程去执行,执行完了就等队列。第四个任务来了,不会直接给线程去执行,而是加到队列,让前3个线程去队列取任务。

Worker里面封装了这个任务,并且里面有一个线程池的线程,总共3个Worker,3个任务(3个第一个任务),3个线程。线程run时候就开一个线程去执行Worker里的第一个任务,线程Thread run的时候,是开一个线程池的线程,然后Thread里面的Runnable的run方法在这个线程里面执行,所以Worker要设置成这个Thread的Runnable,就是Worker的run方法在这个线程里面执行(转调外部类的runWorker方法,把worker传进去)runWorker方法就在这个线程里面执行Worker里面仅仅保存的是这个worker的第一个任务,第一个任务执行完会死循环执行queue队列的任务。

Worker是作为一个Runnable存在于线程池的线程Thread中的所有Worker的方法都在这个线程中执行(多个线程执行Worker类的相同方法)runWorker执行的时候,worker w成为了这个线程的局部变量,w.lock();w.unlock(); 多线程执行同一个方法不要紧,只要不是使用共享变量就没事。由于w不是共享变量,一个线程一个局部变量w,所以不会抢锁一个线程的Worler w不会跑到另一个线程里面去,所以是单线程访问的。

executorService.execute(new Runnable() {} = firstTask);
Worker w = new Worker(firstTask);
Worker(Runnable firstTask) {
    setState(-1);  
    this.firstTask = firstTask; 
    this.thread = getThreadFactory().newThread(this);     
}

 一个线程池线程中一个RunnableWorker,这个RunnableWorker不仅仅执行第一个任务还执行队列的任务,这个Runnable一直不会退出。

所有的任务都在这个线程里面执行,所有的任务都由这个worker执行。

要想w.lock();w.unlock();有线程抢锁,那么一个worker就要被设置到多个线程池的线程去,一个Worker成为多个线程的Runnable,多个线程同时执行时候,这一个Runnable在多个线程中执行,成为多个线程的局部变量ww.lock();w.unlock();就会出现多线程抢锁。但是不行,

线程跟worker是一对一的关系,通过Runnable建立起来的。

其他线程调用中断interrupt相关方法时候,会从workers中获取一个worker,此时worker w就存在于另一个线程中了,就会多个线程使用这个worker w了。此时锁就有意义了。

Worker初始化时候,只会在一个线程池的线程中,是单线程。但是其他线程可以从workers里面获取这个worker,就是多线程访问。

线程池的所有线程全保存workers里面的worker里面的thread上面

超过3个任务进来, 不会创建线程,而是直接丢到队列里面去,然后流程执行完。

Worker继承AQS也就是一个ReentantLock,不同的线程调用worker w的lock和unlock方法可以实现锁的功能,不同的线程可以锁住不同的代码段。


 当一个任务提交至线程池之后,

1. 线程池首先判断核心线程池里的线程是否已经满了。如果不是,则创建一个新的工作线程来执行任务。否则进入2.

2. 判断工作队列是否已经满了,倘若还没有满,将线程放入工作队列。否则进入3.

3. 判断线程池里的线程是否都在执行任务。如果不是,则创建一个新的工作线程来执行。如果线程池满了,则交给饱和策略来处理任务。

RUNNING:111   SHUTDOWN:000    STOP:001    TIDYING:010    TERMINATED:011

SHUTDOWN = 0,STOP|TIDYING|TERMINATED > 0,RUNNING < 0

新建一个线程池时它的状态为Running,这时它不断的从外部接收并处理任务,当处理不过来时它会把任务放到任务队列中;

之后我们可能会调用shutdown()来终止线程池,这时线程池的状态从Running转为Shutdown,它开始拒绝接收从外部传过来的任务,但是会继续处理完任务队列中的任务;

我们也可能调用shutdownNow()来立刻停止线程池,这时线程池的状态从Running转为Stop,然后它会快速排空任务队列中的任务并转到Tidying状态,处于该状态的线程池需要执行terminated()来做相关的扫尾工作,

执行完terminated()之后线程池就转为Terminated状态,表示线程池已终止。这些状态的转换图如下所示。

  • RUNNING:接受新任务并且处理阻塞队列里的任务
  • SHUTDOWN:拒绝新任务但是处理阻塞队列里的任务
  • STOP:拒绝新任务并且抛弃阻塞队列里的任务同时会中断正在处理的任务
  • TIDYING:所有任务都执行完(包含阻塞队列里面任务)当前线程池活动线程为0,将要调用terminated方法
  • TERMINATED:终止状态。terminated方法调用完成以后的状态

线程池状态转换

RUNNING -> SHUTDOWN

   显式调用shutdown()方法, 或者隐式调用了finalize()方法

(RUNNING or SHUTDOWN) -> STOP

   显式调用shutdownNow()方法

SHUTDOWN -> TIDYING

   当线程池和任务队列都为空的时候

STOP -> TIDYING

   当线程池为空的时候

TIDYING -> TERMINATED

    terminated() hook 方法执行完成时候

corePoolSizecorePoolSize –> workQueue –> maximumPoolSize。如果运行的线程少于 corePoolSize,则创建新线程来处理任务,即使线程池中的其他线程是空闲的;当线程池中的线程数量大于等于 corePoolSize 且小于 maximumPoolSize,则只有当workQueue满时才创建新的线程去处理任务;当运行的线程数量大于等于maximumPoolSize,这时如果workQueue已经满了,则通过handler所指定的策略来处理任务;一般来说都会把corePoolSize和maximumPoolSize,设置为一样,这样的话,能够减少线程创建的消耗,直接往阻塞队列中取就可以了.

如果采用无界队列,那么maximumPoolSize将会失去作用,此时一般corePoolSize和maximumPoolSize,设置为一样;

keepAliveTime:线程池维护线程所允许的空闲时间。当线程池中的线程数量大于corePoolSize的时候,如果这时没有新的任务提交,核心线程外的线程不会立即销毁,而是会等待,直到等待的时间超过了keepAliveTime;


 首先是RUNNING状态,然后进入SHUTDOWN和STOP状态,进入SHUTDOWN和STOP状态还有去调整(处理队列任务),调整完最后进入TERMINATED状态。

ctl11100000000000000000000000000000=-536870912开始,慢慢加1,一直越来越大,最后=111111111111111111111111=-1

worker线程数量最大2^29-1=536870911个,就不能再增加了,所以ctl的范围是(-536870912,-1)一直小于0。

当线程池状态改变时候,改变的是前3位,后29位不变,处于别的状态时候继续使用,原来是1110001101010101010RUNNING状态),变成SHUTDWON之后ctl0000001101010101010SHUTDOWN),变成STOP之后是0010001101010101010STOP状态),变成TIDYING后是0100001101010101010TIDYING态),变成TERMINATED后是0110001101010101010TERMINATED态)

RUNNING< SHUTDOWN< STOP< TIDYING< TERMINATED值,大小顺序,基本符合状态的流转过程。

RUNNING<= RUNNINGctl< SHUTDOWN<= SHUTDOWNctl< STOP<= STOPctl< TIDYING<= TIDYINGctl< TERMINATED<=TERMINATEDctl值。

每个状态的ctl值大于等于这个状态的标称值,小于下一个标称值。标称值是0临界值rs后面全是0ctl后面不是0rs可以用=ctl不能用=ctl只能用大于小于。ctlrs用大于小于判断得到的状态是一个区间值,是多个可能的值。

1.处于正常状态的ctlctl=111xxxxxxxxrs=runStateOf(ctl)=RUNNING=111 0000000000000000,RUNNING<=ctl<SHUTDOWN

2.处于关闭状态的ctlctl=000xxxxxxxxrs=runStateOf(ctl)=SHUTDOWN=000 0000000000000000,SHUTDOWN<=ctl<STOP

3.处于停止状态的ctlctl=001xxxxxxxxrs=runStateOf(ctl)=STOP=001 0000000000000000 ,STOP<=ctl<TIDYING

4.处于调整中的ctlctl=010xxxxxxxxrs=runStateOf(ctl)=TIDYING=010 0000000000000000,TIDYING<=ctl<TERMINATED

5.处于调整完毕的ctlctl=011xxxxxxxxrs=runStateOf(ctl)=TERMINATED=011 0000000000000000 ,TERMINATED<=ctl<=2^31-1 

rs只能等于111 0000000000000000(RUNNING)000 0000000000000000(SHUTDOWN)001 0000000000000000(STOP)010 0000000000000000(TIDYING)011 0000000000000000(TERMINATED)

rs>=RUNNINGctl,rs5种状态。

rs>=SHUTDOWNctl,rs4种状态。

rs>=STOPctl,rs3种状态。

rs>=TIDYINGctl,rs2种状态。

rs>=TERMINATEDctl,rs1种状态。

 

ctl>=RUNNINGctl,rs5种状态。

ctl>=SHUTDOWNctl,rs4种状态。

ctl>=STOPctl,rs3种状态。

ctl>=TIDYINGctl,rs2种状态。

ctl>=TERMINATEDctl,rs1种状态。

int rs = runStateOf(c);//前3位不变,后面29位=0

//c处于RUNNING状态,c=111xxxxxxxxx,rs=111 0000000000000000(RUNNING)

//c处于SHUTDOWN状态,c=000xxxxxxxxx,rs=000 0000000000000000(SHUTDOWN)

//c处于STOP状态,c=001xxxxxxxxx,rs=001 0000000000000000(STOP)

//c处于TIDYING状态,c=010xxxxxxxxx,rs=010 0000000000000000(TIDYING)

//c处于TERMINATED状态,c=011xxxxxxxxx,rs=011 0000000000000000(TERMINATED)

正常运行小于0,SHUTDOWN=0,其他STOP,TIDYING,TERMINATED都是大于0

//C的低29位,跟00011111 11111111 11111111 11111111比较,低29位表示线程池中线程数,最大2^29-1。
    private static int workerCountOf(int c) {//对2^29取余,ctl加了多少次1,最大加2^29-1次。表示多少个worker已经在运行了。
        return c & CAPACITY;//00011111 11111111 11111111 11111111
    }


// C的高3位,高3位表示线程池的运行状态。111RUNNING:运行中,接受新任务处理队列中的任务。
//000SHUTDOWN:不接收新任务处理队列中的任务; 001STOP:不接收新任务也不处理队列中的任务还中断正在运行的任务;
//010TIDYING:所有的任务都已经终止;011TERMINATED:terminated()方法已经执行完成 
    private static int runStateOf(int c) {
        return c & ~CAPACITY;//11100000 00000000 00000000 00000000
    }

 

posted @ 2019-08-19 16:14  无天666  阅读(204)  评论(0编辑  收藏  举报