preface

ThreadPoolExecutor handles the state of the thread pool and the size of the thread pool

How do you store the state and the number of worker threads, so let’s take a look at that step by step, and then just to summarize, why do you do that

Analysis of the

    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
    private static final int COUNT_BITS = Integer.SIZE - 3;/ / 32-3 = 29
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;//2 to the 29th minus 1

    // runState is stored in the high-order bits
    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 final int TIDYING    =  2 << COUNT_BITS;
    private static final int TERMINATED =  3 << COUNT_BITS;

    // Packing and unpacking ctl
    private static int runStateOf(int c)     { return c & ~CAPACITY; }
    private static int workerCountOf(int c)  { return c & CAPACITY; }
    private static int ctlOf(int rs, int wc) { return rs | wc; }
Copy the code

This code stores the number of worker threads and the state of the current thread pool

ThreadPoolExecutor uses a CTL to store the current state and the current thread count.

So this one uses three of the 32 bits to store the current thread state, and the last one is used to store the number of threads, so the number of threads, theoretically at most, is 2 to the 29th minus 1. Which is the base 10 value of CAPACITY above.

The operator

Now let’s take a closer look at how it works. Okay? How to store it? How does it work? You might want to learn a few logical operators before you do that

  • The ampersand operator: operator 0&0=0; 1 = 0 0 &; 1 & 0 = 0; 1 &1 = 1; If both bits are 1, the result is 1, otherwise it is 0
  • The operator | or operator: 0 | 0 = 0; 0 | 1 = 1; 1 | 0 = 1; 1 | 1 = 1; In plain English, it’s two bits and if either one of them is a 1 then the result is a 1 or zero;
  • The << left shift operator: for example, 3 <<2. The 8-bit binary of 3 is 0000 0011 and then moved 2 bits to the left gives 0000 1100
  • The ~ not operator: the rule is to invert all binary bits such as the 8-bit binary of 3, 0000, 0011, and the 8-bit binary of 3, 1111, 1100

Well only mastered the above logical operators to understand how to do, otherwise a face meng forced, the university inside learning back to the teacher!

Field analysis

  • COUNTBITS: The value of COUNTBITS is integer. sie-3. Integer is a maximum of 32 bits, and integer. SIZE is also 32.

  • CAPACITY: CAPACITY (1 << COUNTBITS) -1 COUNTBITS (1 << 29) First of all a 32-bit binary is 0000 0000 0000 0000 0000 0000 0000 0001, the left 29 result: 0010 0000 0000 0000 0000 0000 0000 0000, that the results minus 1 is: 0001 1111 1111 1111 1111 1111 1111 1111;

  • RUNNING: the value of RUNNING is -1<< COUNT_BITS, or -1<<29.

    • We know that the maximum size of an Intger is 32 bits, and the maximum capacity is 2 to the power of 32 minus 1. Why is that? Because it’s 32 bits, but the first bit of the binary is the symbol bit that is stored, which is also a positive or negative number. So 2 to the eighth minus 1 is 127,
    • Science is a knowledge point again here we are in the situation of complement system to store, why do you put this not clear Can look at this article: blog.csdn.net/zl10086111/…
    • How is -1 stored if you look at the table below
category 32-bit binary value
The original code 1000 0000 0000 0000 0000 0000 0001
Radix-minus-one complement 1111 1111 1111 1111 1111 1111 1111 1111 1110
complement 1111 1111 1111 1111 1111 1111 1111 1111 1111
< < 29 1110 0000 0000 0000 0000 0000

So I’m not going to go through the last few states,

The status value 32-bit binary value
RUNNING 1110 0000 0000 0000 0000 0000
SHUTDOWN 0000 0000 0000 0000 0000 0000
STOP 0010 0000 0000 0000 0000 0000
TIDYING 0100 0000 0000 0000 0000 0000
TERMINATED 0110 0000 0000 0000 0000 0000 0000

Okay, so once you look at the state up here, what is CTL

ctl

First of all, let’s look at that from the code and see that the CTL is an AtomicInteger type, which is an atomic class, and I’m sure you know about atomic classes, but if you don’t know about atomic classes, you should go and see.

The CTL consists of workerCount, which means the number of runs in the thread word, and runState, which means the state of the thread word.

Our ways of invoking ctlOf, rs | wc is this state of the thread pool size and the number of threads or operations, or operations I also mentioned above, only about one out of two binary bit is 1 the result is 1, that means no matter how much thread pool which runState state and phase or the size of the number of threads, The last 29 bits are the size of the number of threads, for example

The variable name 32-bit binary value
Rs: RUNNING 1110 0000 0000 0000 0000 0000
Wc: 5 0000 0000 0000 0000 0101
CTL: rs or wc 1110 0000 0000 0000 0000 0101

Let’s see if all three bits are saved, and the low value is the size of the number of threads

runStateOf/workerCountOf

The runStateOf method is used to retrieve the current thread pool state. We know that the thread pool state exists in the three digits of the CTL. How do we retrieve the three digits

private static int runStateOf(int c)     { return c & ~CAPACITY; }
private static int workerCountOf(int c)  { return c & CAPACITY; }
Copy the code

So let’s see how it works, c is the value of CTL that we get, and we just use that, right

The variable name 32-bit binary value
C: 1110 0000 0000 0000 0000 0101
CAPACITY 0001 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111
~CAPACITY 1110 0000 0000 0000 0000 0000
c & ~CAPACITY 1110 0000 0000 0000 0000 0000

Let’s see if the result is the value of our RUNNING state. In fact, all the three bits of ~CAPACITY are 1, and all the lower 29 bits are 0. Regardless of the logic and operation of this value and that value, the value obtained retains the result of the three bits.

The variable name 32-bit binary value
W: 0000 0000 0000 0000 0101
CAPACITY 0001 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111
w & CAPACITY 0000 0000 0000 0000 0101

Now, let’s see if this is the same 5 that we had before, because it’s a very clever operation, because it just keeps the low value. It’s the opposite of that.

conclusion

Ok, step by step, through the above analysis, I believe that smart you will be able to understand what’s going on, the author who wrote Juc really fierce, details are very clever use of, really didn’t make a began to see, wait to understand this feeling is really clever, when you look at must to look at the code of Java files, don’t look at the class file code, It’ll be even more confusing if you see it. It’s all numbers!

ThreadPoolExecutor is a JUC package that handles concurrent multithreading in Java. It is not intended to reduce the number of fields that are stored. It is intended to reduce the number of fields that are stored concurrently. To ensure the synchronization of these two fields, although we can use CAS to update the fields, CAS cannot guarantee the same execution of the two fields. If the two fields are merged into one field at this time, I will have no problem using CAS. For example, AtomicInteger compareAndSet is used to create new threads

In JUC, there are many such processes. For example, I remember seeing ReentrantReadWriteLock that stores read/write lock reentrances. ReentrantReadWriteLock also stores read/write lock reentrances. ReentrantReadWriteLock