Heim >Java >javaLernprogramm >Wie kann ich den Java-Thread-Pool ordnungsgemäß herunterfahren?

Wie kann ich den Java-Thread-Pool ordnungsgemäß herunterfahren?

PHPz
PHPznach vorne
2023-04-22 11:46:071145Durchsuche

Shutdown()-Methode

Bei Verwendung des Thread-Pools akzeptiert der Thread-Pool nach dem Aufruf der Shutdown()-Methode keine neuen Ausführungsaufgaben mehr. Allerdings müssen Aufgaben, die vor dem Aufruf der Methode „shutdown()“ in die Aufgabenwarteschlange gestellt wurden, noch ausgeführt werden. Diese Methode ist eine nicht blockierende Methode und kehrt sofort nach dem Aufruf zurück. Sie wartet nicht auf die Ausführung aller Aufgaben in der Aufgabenwarteschlange, bevor sie zurückkehrt. Werfen wir einen Blick auf den Quellcode der Shutdown()-Methode, wie unten gezeigt.

public void shutdown() {
	//获取线程池的全局锁
	final ReentrantLock mainLock = this.mainLock;
	mainLock.lock();
	try {
		//检查是否有关闭线程池的权限
		checkShutdownAccess();
		//将当前线程池的状态设置为SHUTDOWN
		advanceRunState(SHUTDOWN);
		//中断Worker线程
		interruptIdleWorkers();
		//为ScheduledThreadPoolExecutor调用钩子函数
		onShutdown(); // hook for 
	} finally {
		//释放线程池的全局锁
		mainLock.unlock();
	}
	//尝试将状态变为TERMINATED
	tryTerminate();
}

Im Allgemeinen ist der Code der Methode „shutdown()“ relativ einfach. Er prüft zunächst, ob eine Berechtigung zum Schließen des Thread-Pools vorliegt Wenn keine Berechtigung vorliegt, wird eine SecurityException-Ausnahme ausgelöst. Der Code lautet wie folgt.

//检查是否有关闭线程池的权限
checkShutdownAccess();
//将当前线程池的状态设置为SHUTDOWN
advanceRunState(SHUTDOWN);
//中断Worker线程
interruptIdleWorkers();

Unter diesen lautet der Implementierungscode der checkShutdownAccess()-Methode wie folgt.

private void checkShutdownAccess() {
	SecurityManager security = System.getSecurityManager();
	if (security != null) {
		security.checkPermission(shutdownPerm);
		final ReentrantLock mainLock = this.mainLock;
		mainLock.lock();
		try {
			for (Worker w : workers)
				security.checkAccess(w.thread);
		} finally {
			mainLock.unlock();
		}
	}
}

Der Code der checkShutdownAccess()-Methode ist relativ einfach zu verstehen. Er dient dazu, festzustellen, ob Sie die Berechtigung zum Schließen des Thread-Pools haben, während die globale Sperre des Thread-Pools verwendet wird.

Als nächstes schauen wir uns den Quellcode der advancedRunState(int)-Methode an, wie unten gezeigt.

private void advanceRunState(int targetState) {
	for (;;) {
		int c = ctl.get();
		if (runStateAtLeast(c, targetState) ||
			ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
			break;
	}
}

Die Gesamtlogik der advancedRunState(int)-Methode besteht darin, zu bestimmen, ob der aktuelle Thread-Pool-Status der angegebene Status ist. Wenn er SHUTDOWN ist, wird er direkt zurückgegeben. Wenn es nicht SHUTDOWN ist, wird der aktuelle Thread-Pool-Status auf SHUTDOWN gesetzt.

Als nächstes schauen wir uns die Methode interruptIdleWorkers() an, die von der Methode showdown() aufgerufen wird, wie unten gezeigt.

private void interruptIdleWorkers() {
	interruptIdleWorkers(false);
}

Sie können sehen, dass die Methode interruptIdleWorkers() die Methode interruptIdleWorkers(boolean) aufruft. Sehen Sie sich weiterhin den Quellcode der Methode interruptIdleWorkers(boolean) an, wie unten gezeigt.

private void interruptIdleWorkers(boolean onlyOne) {
	final ReentrantLock mainLock = this.mainLock;
	mainLock.lock();
	try {
		for (Worker w : workers) {
			Thread t = w.thread;
			if (!t.isInterrupted() && w.tryLock()) {
				try {
					t.interrupt();
				} catch (SecurityException ignore) {
				} finally {
					w.unlock();
				}
			}
			if (onlyOne)
				break;
		}
	} finally {
		mainLock.unlock();
	}
}

Die Gesamtlogik des obigen Codes lautet: Erhalten Sie die globale Sperre des Thread-Pools, durchlaufen Sie alle Arbeitsthreads, erkennen Sie, ob der Thread unterbrochen ist. Wenn nicht, erhält der Arbeitsthread die Sperre und führen Sie die Unterbrechungsmethode des Threads aus und geben Sie die vom Thread erworbene Sperre frei. Wenn zu diesem Zeitpunkt der Parameter onlyOne wahr ist, verlassen Sie die Schleife. Andernfalls durchlaufen Sie alle Arbeitsthreads und führen den gleichen Vorgang aus. Schließlich wird die globale Sperre des Thread-Pools aufgehoben.

Als nächstes werfen wir einen Blick auf die Methode „shutdownNow()“.

ShutdownNow()-Methode

Wenn die ShutdownNow()-Methode des Thread-Pools aufgerufen wird, akzeptiert der Thread-Pool keine neuen Ausführungsaufgaben mehr und die in der Aufgabenwarteschlange vorhandenen Aufgaben werden verworfen und der ausführende Worker-Thread wird verworfen Gleichzeitig wird die Methode sofort unterbrochen. Diese Methode hat einen Rückgabewert, der die Liste der verworfenen Aufgaben in der aktuellen Aufgabenwarteschlange darstellt.

Der Quellcode der Methode „shutdownNow()“ lautet wie folgt.

public List<Runnable> shutdownNow() {
	List<Runnable> tasks;
	final ReentrantLock mainLock = this.mainLock;
	mainLock.lock();
	try {
		//检查是否有关闭权限
		checkShutdownAccess();
		//设置线程池的状态为STOP
		advanceRunState(STOP);
		//中断所有的Worker线程
		interruptWorkers();
		//将任务队列中的任务移动到tasks集合中
		tasks = drainQueue();
	} finally {
		mainLock.unlock();
	}
	/尝试将状态变为TERMINATED
	tryTerminate();
	//返回tasks集合
	return tasks;
}

Die Gesamtlogik des Quellcodes der Methode „shutdownNow()“ ist grundsätzlich dieselbe wie die der Methode „shutdown()“, außer dass die Methode „shutdownNow()“ den Status des Thread-Pools auf STOP setzt, alle Worker-Threads unterbricht und Verschiebt alle Aufgaben in der Aufgabenwarteschlange in die Aufgabensammlung und gibt sie zurück.

Sie können sehen, dass, wenn die Methode „shutdownNow()“ alle Threads unterbricht, die Methode „interruptWorkers()“ aufgerufen wird. Als Nächstes schauen wir uns den Quellcode der Methode „interruptWorkers()“ an, wie unten gezeigt.

private void interruptWorkers() {
	final ReentrantLock mainLock = this.mainLock;
	mainLock.lock();
	try {
		for (Worker w : workers)
			w.interruptIfStarted();
	} finally {
		mainLock.unlock();
	}
}

Die Logik der interruptWorkers()-Methode ist relativ einfach. Sie besteht darin, die globale Sperre des Thread-Pools zu erhalten, alle Arbeitsthreads zu durchlaufen, die Threads nacheinander zu unterbrechen und schließlich die globale Sperre des Thread-Pools aufzuheben.

Innerhalb der interruptWorkers()-Methode wird tatsächlich die interruptIfStarted()-Methode der Worker-Klasse aufgerufen, um den Thread zu unterbrechen. Schauen wir uns den Quellcode der interruptIfStarted()-Methode der Worker-Klasse an, wie unten gezeigt.

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

stellte fest, dass es im Wesentlichen die interrupt()-Methode der Thread-Klasse aufruft, um den Thread zu unterbrechen.

awaitTermination(long, TimeUnit)-Methode

Wenn der Thread-Pool die Methode waitingTermination(long, TimeUnit) aufruft, blockiert sie den Thread des Aufrufers und kehrt erst zurück, wenn der Status des Thread-Pools in TERMINATED geändert wird oder das Zeitlimit überschritten wird Zeitraum erreicht ist. Schauen wir uns als Nächstes den Quellcode der Methode „awaitTermination(long, TimeUnit)“ an, wie unten gezeigt.

public boolean awaitTermination(long timeout, TimeUnit unit)
	throws InterruptedException {
	//获取距离超时时间剩余的时长
	long nanos = unit.toNanos(timeout);
	//获取Worker线程的的全局锁
	final ReentrantLock mainLock = this.mainLock;
	//加锁
	mainLock.lock();
	try {
		for (;;) {
			//当前线程池状态为TERMINATED状态,会返回true
			if (runStateAtLeast(ctl.get(), TERMINATED))
				return true;
			//达到超时时间,已超时,则返回false
			if (nanos <= 0)
				return false;
			//重置距离超时时间的剩余时长
			nanos = termination.awaitNanos(nanos);
		}
	} finally {
		//释放锁
		mainLock.unlock();
	}
}

Die Gesamtlogik des obigen Codes lautet: Rufen Sie zuerst die exklusive Sperre des Worker-Threads ab und ermitteln Sie dann in einer Schleife, ob sich der aktuelle Thread-Pool bereits im Status TERMINATED befindet. Wenn ja, geben Sie direkt true zurück, andernfalls prüfen Sie, ob dies der Fall ist ist abgelaufen. Wenn es abgelaufen ist, geben Sie false zurück. Wenn es nicht zu einer Zeitüberschreitung kommt, setzen Sie die verbleibende Zeit vor der Zeitüberschreitung zurück. Geben Sie als Nächstes den nächsten Zyklus ein und prüfen Sie erneut, ob sich der aktuelle Thread-Pool im Status TERMINATED befindet. Andernfalls prüfen Sie, ob eine Zeitüberschreitung aufgetreten ist, und geben Sie false zurück. Wenn es nicht zu einer Zeitüberschreitung kommt, setzen Sie die verbleibende Zeit vor der Zeitüberschreitung zurück. Diese Schleife wird fortgesetzt, bis der Status des Thread-Pools TERMINATED lautet oder eine Zeitüberschreitung vorliegt.

Das obige ist der detaillierte Inhalt vonWie kann ich den Java-Thread-Pool ordnungsgemäß herunterfahren?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen