[JUC 소스 코드] 스레드 풀 : ThreadPoolExecutor (3) 작업자 설계 및 소스 코드 분석

스레드 풀 시리즈 :

작업자 디자인 아이디어

이론적으로 스레드 풀은 많은 스레드를 유지하는 것이며 각 스레드는 많은 작업을 가질 수 있습니다. 하지만 여기에 문제가 있습니다.

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

그러면이 스레드가 실행 된 후 hello를 인쇄하는 작업이 종료되고 스레드를 재사용 하여 여러 작업을 수행하는 것은 불가능 합니다. 따라서 Thread를 생성 할 때 특정 작업을 넣는 것이 아니라 Runnable을 다시 캡슐화하고 다음과 같은 run 메소드에서 작업을 얻기위한 특정 메소드를 호출해야합니다.

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

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

위에서 말한 것을 이해 한 후에 ThreadPoolExecutor의 핵심 논리는 실제로 거의 명확합니다.

작업자 소스 코드 분석

스레드 풀에서 가장 작은 작업 실행 단위입니다.

ThreadPoolExecutor의 Worker는 위에서 말한 것보다 더 독창적입니다 .Runnable을 다시 캡슐화하는 것이 아니라 Runnable 인터페이스를 구현하면서 Thread를 캡슐화하여 스레드 재사용의 목적을 달성합니다 (예 : new Thread (this)).

또한 Worker는 스레드 생성시 첫 번째 작업 인 firstTask도 저장하지만 firstTask가 실행되면 null로 설정되고 getTask ()를 통해 작업 대기열에서 새로운 작업을 지속적으로 가져 와서 실행할 수 있습니다.

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);
    }
}

추신 : 너무 많은 스레드가 생성되고 많은 스레드가 작업없이 유휴 상태이면 어떻게됩니까?
답변 : 스레드가 작업 실행을 기다리기에 너무 늦으면 재활용됩니다 특정 재활용 전략은 getTask () 메서드에서 볼 수 있습니다.

또한 Worker 자체 도 AQS를 구현 하므로 잠금이기도합니다. 작업을 수행 할 때 자체적으로 잠 깁니다. 작업이 완료된 후 자신을 해제하여 스레드가 작업을 실행할 때 다른 스레드로 던져 지도록합니다. 작업입니다. 관련 방법은 다음과 같습니다.

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) {
    
    
           }
       }
}                                        

추천

출처blog.csdn.net/weixin_43935927/article/details/113966417