如何停止一個正在運行的線程?

如何停止一個正在運行的線程? 這個一個面試常問的問題, 我們有兩種辦法, 分別是stop()和interrupt(), 但stop()太過於暴力, 無法保證線程業務的原子性, 且已過期, 不推薦使用.

使用stop()來停止線程

stop()方法讓線程立即停止運行, 這種暴力停止可能會破壞線程業務的原子性, 如下所示:

static class MyThread extends Thread {
	@Override
	public void run() {
		while (true) {
			System.out.println("線程開始執行...");
			System.out.println("業務步驟1");
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("業務步驟2");
			System.out.println("線程執行完畢...");
		}
	}
}

public static void main(String[] args) {
	MyThread thread = new MyThread();
	thread.start();

	try {
		Thread.sleep(2000);
		thread.stop();
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
}

執行結果爲:

線程開始執行...
業務步驟1

使用interrupt() + return來停止線程

線程調用interrupt()會生成一箇中斷標記, 在線程邏輯中通過isInterrupted()判斷是否存在中斷標記, 存在則return.

static class MyThread extends Thread {
	@Override
	public void run() {
		for (int i = 0; i < 500000; i++) {
			if (this.isInterrupted()) {
				System.out.println("線程終止, 停止for循環.");
				return;
			}
			System.out.println("i=" + (i + 1));
		}
	}
}

public static void main(String[] args) {
	MyThread thread = new MyThread();
	thread.start();

	try {
		Thread.sleep(200);
		thread.interrupt();
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
}

結果:

i=38319
i=38320
i=38321
線程終止, 停止for循環.

使用interrupt() + InterruptedException來停止線程

線程調用interrupt()會生成一箇中斷標記, 在線程邏輯中通過isInterrupted()判斷是否存在中斷標記, 存在則拋出一個InterruptedException, 同時捕獲它.

static class MyThread extends Thread {
	@Override
	public void run() {
		try {
			for (int i = 0; i < 100000; i++) {
				if (this.isInterrupted()) {
					System.out.println("線程終止, 停止for循環.");
					throw new InterruptedException();
				}
				System.out.println("i=" + (i + 1));
			}
		} catch (InterruptedException e) {
			System.out.println("MyThread拋出InterruptedException.");
			e.printStackTrace();
		}
	}
}

public static void main(String[] args) {
	MyThread thread = new MyThread();
	thread.start();

	try {
		Thread.sleep(200);
		thread.interrupt();
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
}

結果:

i=34901
i=34902
i=34903
線程終止, 停止for循環.
MyThread拋出InterruptedException.
java.lang.InterruptedException
	at org.tyshawn.thread.ThreadTest$MyThread.run(ThreadTest.java:27)

interrupt()遇到sleep(), join()和wait()會拋出一個InterruptedException

當線程是阻塞狀態時, 這時調用interrupt()方法會拋出一個InterruptedException.

	static class MyThread extends Thread {
	@Override
	public void run() {
		try {
			System.out.println("線程開始執行");
			Thread.sleep(300);
			//this.join();
			//this.wait();
			System.out.println("線程執行完畢");
		} catch (InterruptedException e) {
			System.out.println("MyThread拋出InterruptedException.");
			e.printStackTrace();
		}
	}
}

public static void main(String[] args) {
	MyThread thread = new MyThread();
	thread.start();

	try {
		Thread.sleep(200);
		thread.interrupt();
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
}

結果:

線程開始執行
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at org.tyshawn.thread.ThreadTest$MyThread.run(ThreadTest.java:56)
MyThread拋出InterruptedException.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章