스레드 풀 시리즈 :
- [JUC 소스 코드] 스레드 풀 : ThreadPoolExecutor (1) 상속 관계 분석
- [JUC 소스 코드] 스레드 풀 : ThreadPoolExecutor (2 개) 기본 구조 분석
- [JUC 소스 코드] 스레드 풀 : ThreadPoolExecutor (3) 작업자 설계 아이디어 및 소스 코드 분석
- [JUC 소스 코드] 스레드 풀 : ThreadPoolExecutor (4) 작업 실행 프로세스의 소스 코드 분석
- [JUC 소스 코드] 스레드 풀 : ThreadPoolExecutor (5) 요약
- [JUC 소스 코드] 스레드 풀 : 스레드 풀 생성을위한 매개 변수 설정 아이디어 & Excutors
- [JUC 소스 코드] Thread Pool : ThreadPool에 대한 몇 가지 질문
작업자 디자인 아이디어
이론적으로 스레드 풀은 많은 스레드를 유지하는 것이며 각 스레드는 많은 작업을 가질 수 있습니다. 하지만 여기에 문제가 있습니다.
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) {
}
}
}