线程池源码的基础属性和方法
在线程池的源码中,会通过一个AtomicInteger类型的变量ctl,来表示线程池的状态和当前线程池中的工作线程数。 一个Integer占4个字节,也就是32bit,对应线程池的五种状态:
- RUNNING
可以接收新的任务,同时可以去处理队列中的任务
- SHUTDOWN
不能接收新的任务,但是会去处理队列中的任务----优雅的关闭线程池(处理完剩余的任务)
- STOP
不能接收新的任务,且不能处理队列中的任务,并且中断处理中的任务(一个任务能不能被中断得看任务本身)
- TIDYING
所有的任务都结束了,线程池中也没有线程了,状态将转到Terminated状态,一旦到达此状态,就会调用线程池的terminated()--这个方法可以自定义,执行完这个方法之后线程池的状态就会变成Terminated状态 terminated()方法执行完成之后就会转变为TERMINATED
All tasks have terminated, workerCount is zero, the thread transitioning to state TIDYING will run the terminated() hook method
- TERMINATED
terminated() has completed The numerical order among these values matters, to allow ordered comparisons
只要线程池中的状态变成了Terminated状态,线程池中就没有线程了,如果线程池的状态是Terminated,表示线程池已经执行terminated方法了。
2个bit能表示4种状态(00,01,11,10),那5种状态至少需要3个bit位,在线程池的源码中是这么表示的。
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static int TIDYING = 2 << COUNT_BITS;
private static int TERMINATED = 3 << COUTN_BITS;
Integer.SIZE是一个Java的静态字段,它返回一个整数类型(int)的大小,即在内存中所占用的位数(bit)。在Java中,Integer.SIZE的值始终为32,表示一个int类型占用32个位。
需要注意的是,32位并不是
int类型的实际大小(字节数),而是表示使用32个二进制位来存储一个整数值。在Java中,int类型的大小是固定的4个字节(32位),因此实际上是占用4个字节的存储空间。
这样设计的好处是,可以在不同的平台和系统上保持
int类型的大小一致,确保代码的可移植性。
Integer.SIZE 为32 ,所以COUNT_BITS为29,最终各个状态对应的二进制为:
- RUNNING:11100000 00000000 00000000 00000000
- SHUTDOWN:00000000 00000000 00000000 00000000
- STOP:00100000 00000000 00000000 00000000
- TIDYING:01000000 00000000 00000000 00000000
- TERMINATED:01100000 00000000 00000000 00000000
因此只需要使用一个Integer的最高三个bit,就可以表示线程池的5种状态,而剩下的29位表示工作线程数。
一个线程在执行任务的时候被中断了,在获取下一个任务的时候,发现线程池的状态为SHUTDOWN状态,这个时候线程退出。 线程被阻塞时候中断线程池-----抛出异常退出
shutdownNow方法中断所有的线程,shutdown方法中断空闲的线程----tryLock判断是否是中断的线程,能够加到锁表示线程没有在执行任务-----线程是空闲的(shutdown会留一部分线程执行队列中的任务)。线程池中的线程在执行任务的时候会加锁,加锁去执行任务,如果说拿不到锁,说明没拿到锁的线程空闲。