[JUC source code] Thread pool: ThreadPoolExecutor (3) Worker design and source code analysis

Thread pool series:

Worker design ideas

In theory, the thread pool is to maintain many threads, and then each thread can have many tasks. But here is a problem. If we directly pass in a specific Runnable when creating a thread, such as

new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                System.out.println("hello");
            }
        }).start();

Then, the task of printing hello is over after this thread executes, and it is impossible to reuse threads to perform multiple tasks. Therefore, it is necessary not to put specific tasks when creating Thread, but to encapsulate Runnable again, and call a specific method for obtaining tasks in its run method, such as the following:

public class Work implements Runnable {
    
    
        @Override
        public void run() {
    
    
        	// runwork 方法才是真正执行任务的方法
            runwork();
        }
    }

main() {
    
    
	// 创建线程时传入 work,调用逻辑就是 Work#run() -> runwork() -> 具体Runnable的run()
	// 所以,只要保证 runwork 方法能一直获取任务,则该线程就能一直运行
	// 另外,在 runwork 获取任务时,还可以扩展线程回收策略,因为只要该方法返回了,该线程就该结束了
	new Thread(Work).start();
}

After understanding what I said above, the core logic of ThreadPoolExecutor is actually almost clear.

Worker source code analysis

The smallest unit of task execution in the thread pool.

The Worker of ThreadPoolExecutor is more ingenious than what I said above. It is not aimed at re-encapsulating Runnable, but encapsulating Thread while also implementing the Runnable interface, thus achieving the purpose of thread reuse (ie new Thread(this)) .

In addition, Worker also saves the first task firstTask when the thread is created, but after firstTask is executed, it will be set to null, and then new tasks will be continuously obtained from the task queue through getTask() to execute.

private final class Worker
    extends AbstractQueuedSynchronizer
    implements Runnable
{
    
    
	// 执行当前 worker 的线程
	final Thread thread;
	// 创建该线程时的任务(第一个任务),执行完后=null
    Runnable firstTask;
	
	// 在创建 worker 的时候创建 Thread
	Worker(Runnable firstTask) {
    
    
		// 将AQS的状态设置为-1
		// 从后面的isLocked方法可以看到,state!=0 表示已经被加锁
	    setState(-1); // inhibit interrupts until runWorker
	    this.firstTask = firstTask;
		// !!!为了线程的复用,Worker本身实现了 Runnable,并且把自己作为任务传递给 thread。非常巧妙的设计!
	    this.thread = getThreadFactory().newThread(this);
	}
	
	// 调用逻辑:Woker#run -> runWorker() -> 具体Runnable的run()
	// runWorker 获取任务的方式有二:
	// 1.firstTask,执行完就置为 null
	// 2.getTask() 不断从从阻塞队列中获取
    public void run() {
    
    
        runWorker(this);
    }
}

PS: What if there are too many threads created, and many threads are idle without tasks?
Answer: If a thread is too late to wait for task execution, it will be recycled. The specific recycling strategy can be seen in the getTask() method.

In addition, the Worker itself also implements AQS , so it is also a lock. It will lock itself when performing tasks. After the task is completed, it will release itself, ensuring that it will be thrown into another thread when a thread executes the task. Task. The related methods are as follows:

public void lock()        {
    
     acquire(1); }
public boolean tryLock()  {
    
     return tryAcquire(1); }
public void unlock()      {
    
     release(1); }
public boolean isLocked() {
    
     return isHeldExclusively();  // Lock methods    
                           
// 尝试加锁,CAS 赋值为 1,表示锁住
protected boolean tryAcquire(int unused) {
    
    
    if (compareAndSetState(0, 1)) {
    
    
        setExclusiveOwnerThread(Thread.currentThread());
        return true;
    }
    return false;
}

// 尝试释放锁,释放锁没有 CAS 校验,可以任意的释放锁
protected boolean tryRelease(int unused) {
    
    
    setExclusiveOwnerThread(null);
    setState(0);     
    return true; 
}

// 0 代表没有锁住,否则代表锁住(-1,1)
protected boolean isHeldExclusively() {
    
    
    return getState() != 0;
}

void interruptIfStarted() {
    
    
       Thread t;
       if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
    
    
           try {
    
    
               t.interrupt();
           } catch (SecurityException ignore) {
    
    
           }
       }
}                                        

Guess you like

Origin blog.csdn.net/weixin_43935927/article/details/113966417