[#0x004B] Java多线程:终止线程的方法

本文介绍如何优雅地终止Java线程,避免使用Thread类的stop()和suspend()方法导致资源未关闭的问题。提供了三种方法:使用中断、使用标志位及使用线程池,并附带示例代码。

  虽说Thread类提供了stop()和suspend()方法,但这两种方法过于粗暴,如果线程占用了一些资源(如打开了一个文件,建立了一个数据库连接什么的),直接stop()或是suspend()是会产生问题的。

 

  要终止Thread,最好的方法就是让run()方法正常运行完毕,不过有的run()方法里面直接是一个while (true),这时就要使用一些特殊的手段。

 

1. 使用中断

  基本思想就是在run()方法中的while (true)里检查线程是否中断,如果中断就退出(当然,退出之前可以做一些关闭资源的操作);这么一来在主线程中就可以调用Thread.interrupt()来中断线程,进而使线程退出。

public class Runner3 implements Runnable {   
	@Override  
	public void run() {   
		while(true) {   
			System.out.println(new Date());   
               
			long time = System.currentTimeMillis();   
			while (System.currentTimeMillis() - time < 1000) {   
				// 不使用Thread.sleep(1000)   
				// 使用while来消耗一秒钟时间   
			}   
               
			if (Thread.currentThread().isInterrupted()) { // 时刻检查该线程是否中断   
			// 或者使用 if (Thread.interrupted()) {   
				return; // 如果线程中断就退出   
			}   
		}   
	}   
}  

 

public class MultiThreadTest3 {   
	public static void main(String[] args) {   
		Runner3 r = new Runner3();   
  
		Thread t = new Thread(r);   
		t.start();   
           
		try {   
			Thread.sleep(10000);   
		} catch (InterruptedException e) {   
			// do nothing   
		}   
           
		t.interrupt(); // 中断Thread t,使run()方法退出,线程结束   
	}   
}  

 

  如果在run()方法中的while (true)里有可能导致InterruptedException的操作,那么退出run()方法的代码可以放在catch语句里。

public class Runner2 implements Runnable {
	@Override
	public void run() {
		while(true) {
			System.out.println(new Date());
			
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				return; // 发生中断异常时,线程直接退出
			}
		}
	}
} 

 

public class MultiThreadTest2 {   
	public static void main(String[] args) {   
		Runner2 r = new Runner2();   
  
		Thread t = new Thread(r);   
		t.start();   
           
		try {   
			Thread.sleep(10000);   
		} catch (InterruptedException e) {   
			// do nothing   
		}   
           
		t.interrupt(); // 中断Thread t,使t.sleep()时产生中断异常,进而终止线程   
	}   
}  

 

2. 使用标志位

   使用标志位boolean flag,将run()方法中的while (true)改为while (flag)(轮询标志位),主线程中就就可以通过修改flag来退出线程。

public class Runner4 implements Runnable {
	private boolean flag = true;
	
	public void setFlag(boolean flag) {
		this.flag = flag;
	}

	@Override
	public void run() {
		while(flag) {
			System.out.println(new Date());
			
			long time = System.currentTimeMillis();
			while (System.currentTimeMillis() - time < 1000) {
				// 不使用Thread.sleep(1000)
				// 使用while来消耗一秒钟时间
			}
		}
	}
}

 

public class MultiThreadTest4 {
	public static void main(String[] args) {
		Runner4 r = new Runner4();

		Thread t = new Thread(r);
		t.start();
		
		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			// do nothing
		}
		
		r.setFlag(false); // 设置标志位,使run()方法退出,线程结束
	}
}

 

  这个方法有一个缺点:如果while (flag) {...}方法阻塞了,则flag的设置会失效。

 

 

 

 

3. 最好的方法是使用线程池

  当线程不用了,就让它sleep并放进队列中,这样可以最大限度地利用资源。不过这暂时不在本文的讨论范围内。

 

 

2010-10-04 补充:
  注意这里说的退出是这样的一种情况:主线程(比如说 main 方法)创建了一个 Thread t,然后想在主线程中使t退出。
  文章一开始说的 stop()、suspend() 方法的问题是:主线程一句 t.stop() 或是 t.suspend() 就了事了,t 在 run() 方法中没有机会去关闭资源,不像中断或是轮询标志位的方法中,t 在 run() 方法里还握有一点主动权

 

 

2011-11-03 补充:

  方法2可以使用的一个优化步骤是将标志位设置为 volatile

我的代码在烧录后,启动监视器显示ELF file SHA256: 9fa0bcf41 Rebooting... ESP-ROM:esp32c3-api1-20210207 Build:Feb 7 2021 rst:0xc (RTC_SW_CPU_RST),boot:0xd (SPI_FAST_FLASH_BOOT) Saved PC:0x4038086a --- 0x4038086a: esp_restart_noos at F:/esp/Espressif/frameworks/esp-idf-v5.5/components/esp_system/port/soc/esp32c3/system_internal.c:115 SPIWP:0xee mode:DIO, clock div:1 load:0x3fcd5820,len:0x15c0 load:0x403cbf10,len:0xc34 load:0x403ce710,len:0x2ff0 entry 0x403cbf1a I (35) boot: ESP-IDF HEAD-HASH-NOTFOUND 2nd stage bootloader I (35) boot: compile time Sep 3 2025 14:38:23 I (35) boot: chip revision: v0.4 I (36) boot: efuse block revision: v1.3 I (40) boot.esp32c3: SPI Speed : 80MHz I (44) boot.esp32c3: SPI Mode : DIO I (47) boot.esp32c3: SPI Flash Size : 2MB I (51) boot: Enabling RNG early entropy source... I (56) boot: Partition Table: I (58) boot: ## Label Usage Type ST Offset Length I (65) boot: 0 nvs WiFi data 01 02 00009000 00006000 I (71) boot: 1 phy_init RF data 01 01 0000f000 00001000 I (78) boot: 2 factory factory app 00 00 00010000 00100000 I (84) boot: End of partition table I (87) esp_image: segment 0: paddr=00010020 vaddr=3c090020 size=1f3f8h (127992) map I (115) esp_image: segment 1: paddr=0002f420 vaddr=3fc93c00 size=00bf8h ( 3064) load I (116) esp_image: segment 2: paddr=00030020 vaddr=42000020 size=8ea70h (584304) map I (212) esp_image: segment 3: paddr=000bea98 vaddr=3fc947f8 size=0156ch ( 5484) load I (213) esp_image: segment 4: paddr=000c000c vaddr=40380000 size=13b74h ( 80756) load I (231) esp_image: segment 5: paddr=000d3b88 vaddr=50000000 size=00020h ( 32) load I (237) boot: Loaded app from partition at offset 0x10000 I (237) boot: Disabling RNG early entropy source... I (248) cpu_start: Unicore app I (257) cpu_start: Pro cpu start user code I (257) cpu_start: cpu freq: 160000000 Hz I (257) app_init: Application information: I (257) app_init: Project name: hidd_demos I (261) app_init: App version: 1 I (265) app_init: Compile time: Sep 3 2025 14:37:57 I (270) app_init: ELF file SHA256: 9fa0bcf41... I (274) app_init: ESP-IDF: HEAD-HASH-NOTFOUND I (279) efuse_init: Min chip rev: v0.3 I (283) efuse_init: Max chip rev: v1.99 I (287) efuse_init: Chip rev: v0.4 I (291) heap_init: Initializing. RAM available for dynamic allocation: I (297) heap_init: At 3FC9A4B0 len 00025B50 (150 KiB): RAM I (302) heap_init: At 3FCC0000 len 0001C710 (113 KiB): Retention RAM I (308) heap_init: At 3FCDC710 len 00002950 (10 KiB): Retention RAM I (314) heap_init: At 50000020 len 00001FC8 (7 KiB): RTCRAM I (320) spi_flash: detected chip: generic I (323) spi_flash: flash io: dio W (326) spi_flash: Detected size(4096k) larger than the size in the binary image header(2048k). Using the size in the binary image header. I (338) sleep_gpio: Configure to isolate all GPIO pins in sleep state I (344) sleep_gpio: Enable automatic switching of GPIO sleep configuration I (351) coexist: coex firmware version: 831ec70 I (370) coexist: coexist rom version 9387209 I (370) main_task: Started on CPU0 I (370) main_task: Calling app_main() I (370) BLE_INIT: BT controller compile version [4713a69] I (370) BLE_INIT: Feature Config, ADV:1, BLE_50:0, DTM:1, SCAN:1, CCA:0, SMP:1, CONNECT:1 I (380) BLE_INIT: Bluetooth MAC: 90:e5:b1:46:9c:06 I (380) phy_init: phy_version 1201,bae5dd99,Mar 3 2025,15:36:21 Guru Meditation Error: Core 0 panic&#39;ed (Load access fault). Exception was unhandled. Core 0 register dump: MEPC : 0x400587d2 RA : 0x4200cd86 SP : 0x3fc9d110 GP : 0x3fc94400 --- 0x400587d2: __strtok_r in ROM --- 0x4200cd86: ble_hid_init_config at F:/esp/Espressif/frameworks/esp-idf-v5.5/components/esp_hid/src/ble_hidd.c:687 TP : 0x3fc9d270 T0 : 0x4005890e T1 : 0x0000000f T2 : 0x0000902d --- 0x4005890e: _data_end_btdm_rom in ROM S0/FP : 0x3c0a72b0 S1 : 0x3fcad454 A0 : 0x3fcaeed0 A1 : 0x09ff0106 A2 : 0x0000a101 A3 : 0x3fcaeed0 A4 : 0x3fcb8fd1 A5 : 0x3fcaeed0 A6 : 0x00000000 A7 : 0x0000000f S2 : 0x3fcaeed0 S3 : 0x00000000 S4 : 0x3fc9d1a4 S5 : 0x00000000 S6 : 0x0000a101 S7 : 0x00000000 S8 : 0x00000000 S9 : 0x00000000 S10 : 0x00000000 S11 : 0x00000000 T3 : 0x00000000 T4 : 0x0000d740 T5 : 0x00000000 T6 : 0x8c154c98 MSTATUS : 0x00001881 MTVEC : 0x40380001 MCAUSE : 0x00000005 MTVAL : 0x09ff0106 --- 0x40380001: _vector_table at F:/esp/Espressif/frameworks/esp-idf-v5.5/components/riscv/vectors_intc.S:54 MHARTID : 0x00000000 Stack memory: 3fc9d110: 0x00000000 0x00000000 0x3fc970a4 0x3fc9d1a4 0x4200bdfe 0x3fca90d8 0x00000000 0x4200cfc8 --- 0x4200bdfe: hidd_event_adapter at F:/esp/ble_hid_device_demo/main/ble_hidd_demo_main.c:300 --- 0x4200cfc8: esp_ble_hidd_dev_init at F:/esp/Espressif/frameworks/esp-idf-v5.5/components/esp_hid/src/ble_hidd.c:984 3fc9d130: 0x00000000 0x00000000 0x3fc9d17c 0x00000005 0x3c095358 0x00000001 0x00001000 0x7fffffff 3fc9d150: 0x00000000 0x00000001 0x0000002c 0x4200bdfe 0x3fc9d1a4 0x00000001 0x3fca90d8 0x4200c41c --- 0x4200bdfe: hidd_event_adapter at F:/esp/ble_hid_device_demo/main/ble_hidd_demo_main.c:300 --- 0x4200c41c: esp_hidd_dev_init at F:/esp/Espressif/frameworks/esp-idf-v5.5/components/esp_hid/src/esp_hidd.c:32 3fc9d170: 0x00000000 0x00000003 0x00000000 0x00000000 0x00000000 0x00000003 0x3c093000 0x4200c202 --- 0x4200c202: app_main at F:/esp/ble_hid_device_demo/main/ble_hidd_demo_main.c:355 3fc9d190: 0x00000000 0x3fc9d20c 0x3c093534 0x4208e948 0x00001800 0x56781234 0x00000100 0x3c094c7c --- 0x4208e948: log_level_get at F:/esp/Espressif/frameworks/esp-idf-v5.5/components/log/src/log_level/tag_log_level/tag_log_level.c:81 3fc9d1b0: 0x3c094f38 0x3c094f4c 0x3c0a72b0 0x00000026 0x5a5aa5a5 0x02505080 0x00171000 0x00000601 3fc9d1d0: 0x001e0000 0x01000000 0x00000000 0x000b0000 0x00000001 0x00640000 0x00000000 0x01010000 3fc9d1f0: 0x004b0005 0x00000000 0x01000000 0x01000001 0x01010001 0x00000000 0x00000000 0x00000100 3fc9d210: 0x3c093534 0x00000003 0x3c093000 0x4208deec 0x00000000 0x00001388 0x00000001 0x00000000 --- 0x4208deec: main_task at F:/esp/Espressif/frameworks/esp-idf-v5.5/components/freertos/app_startup.c:209 3fc9d230: 0x00000000 0x00000000 0x00000000 0x4038b784 0x00000000 0x00000000 0x00000000 0x00000000 --- 0x4038b784: vPortTaskWrapper at F:/esp/Espressif/frameworks/esp-idf-v5.5/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c:258 3fc9d250: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 3fc9d270: 0xa5a5a5a5 0xa5a5a5a5 0x00000150 0x3fc9d040 0x00000000 0x3fc95f40 0x3fc95f40 0x3fc9d27c 3fc9d290: 0x3fc95f38 0x00000018 0x00000000 0x00000000 0x3fc9d27c 0x00000000 0x00000001 0x3fc9c278 3fc9d2b0: 0x6e69616d 0x00000000 0x00000000 0x00000000 0x3fc9d270 0x00000001 0x00000000 0x00000000 3fc9d2d0: 0x00000000 0x00000000 0x3fc9aae8 0x3fc9ab50 0x3fc9abb8 0x00000000 0x00000000 0x00000001 3fc9d2f0: 0x00000000 0x00000000 0x00000000 0x420058be 0x00000000 0x00000000 0x00000000 0x00000000 --- 0x420058be: esp_cleanup_r at F:/esp/Espressif/frameworks/esp-idf-v5.5/components/newlib/src/newlib_init.c:42 3fc9d310: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 3fc9d330: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 3fc9d350: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 3fc9d370: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 3fc9d390: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 3fc9d3b0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000600 3fc9d3d0: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 3fc9d3f0: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 3fc9d410: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 3fc9d430: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 3fc9d450: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 3fc9d470: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 3fc9d490: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 3fc9d4b0: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 3fc9d4d0: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 3fc9d4f0: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
09-04
0x0000: e880 880e a7cb 0080 e174 442f 0800 4500 0x0010: 0428 290a 0000 ff06 09a5 c0a8 01e7 c0a8 0x0020: 01e9 f4c8 2000 5b0e 6c4b e6ec 086b 5010 0x0030: 1000 ae80 0000 01b6 fef4 0004 06f0 e9c0 0x0040: f21c 0bbf 0012 022d 022a 023a 05f5 ff90 0x0050: 08eb f62d e6a8 03ea 06d0 ffb1 05fd ff77 0x0060: 03b5 ffa8 0165 064b eb0c f327 07e2 feb5 0x0070: 0540 046b 04a1 0300 fbd3 0a99 fb03 e9a4 0x0080: 04c9 0529 008c 0719 0294 0615 02f2 02dd 0x0090: 0763 ed24 f6f0 0ae8 fe45 02c0 0381 04d2 0x00a0: 0790 02d4 0b34 fb74 ebfa 067d 0993 03df 0x00b0: 08b3 0475 0823 05e3 070e 0942 f0c2 f4c6 0x00c0: 08f2 0727 080f 0682 0973 0a1b 05ee 0ecd 0x00d0: fde3 efaf 097e 0b61 08eb 0be7 07d6 0d2f 0x00e0: 072f 0975 0a1c ef49 fd50 113b 0471 0a9f 0x00f0: 0744 0997 0bbb f547 061f 023a ee6c 0a7d 0x0100: 0b89 0539 0b0d 07ee 0ba7 0631 0a5f 0845 0x0110: edf3 fcc5 0ffa 0406 0a74 0742 05fd 07df 0x0120: 0471 0d4a f952 ec9f 09bc 09fd 04ff 0991 0x0130: 042f 0941 0375 07b3 074e e8fb f878 0e0a 0x0140: 03dc 06e2 ff16 03a9 08a7 01fd 0bcd f789 0x0150: eb2d 081e 0610 02db 06bb 0259 073f 02b6 0x0160: 067d 04a5 e992 fa94 0bd5 feb3 0323 03f8 0x0170: 03b5 03bc fe34 09e4 f4a5 eb1e 08bf 04d7 0x0180: 0122 06a2 01ce 0512 008a 05e9 01df e6b1 0x0190: f908 0afa fe43 0551 0190 0032 0323 fff5 0x01a0: 07ac f3a4 eadf 0658 03d7 001c 04a3 feb6 0x01b0: 039f fc4f 02b8 01c7 e8e4 fad0 0858 fe60 0x01c0: 0477 00b6 0061 0034 fd87 0794 f1a5 eaa4 0x01d0: 0629 0203 017d 04f1 fea4 02d7 fdb7 055a 0x01e0: 00dd e537 fa20 0871 fe37 04c8 0033 031e 0x01f0: 023d fdcd 0696 f044 ea3c 06e0 00ba fe3a 0x0200: 0215 001c 0639 fd8c 03fd ff67 e623 fb92 0x0210: 0298 f982 051a 004b 02ba 0150 fd21 0539 0x0220: edb7 ebc2 0746 0110 0160 03bd ff34 0414 0x0230: fea8 0503 ffd3 e5b4 fa07 0680 fb0a 011d 0x0240: ff84 02de 0186 0019 0882 ef09 eda0 0636 0x0250: 01af 0069 0290 0080 fceb f660 07f0 fc86 0x0260: e600 fea1 05a2 fc44 022c 0024 0412 0153 0x0270: ffbf 0648 edba ea67 ff20 fab8 0362 0695 0x0280: 004e 0618 0111 089c fe4f e86a 0087 09b1 0x0290: 0001 071b 0264 0438 0341 02d5 07e8 edf7 0x02a0: ee07 086a 007d 0190 03d7 021b 07d0 ffd3 0x02b0: 0924 fdd8 e80d 021e fb87 f717 0981 ff4c 0x02c0: 036e 0246 023c 085e ec9f f02b 0bf3 0105 0x02d0: 0493 03a4 ffe9 0674 00b7 092e fd41 e595 0x02e0: 02d3 09d8 0058 082a 01cf 03b5 0316 0338 0x02f0: 08c1 ee47 f060 0d1f fe7f f5c6 035b 0478 0x0300: 03c0 0100 08f4 f80c e82f 031a 0818 01b5 0x0310: 06e6 0169 05ae 00e4 047a 064c ed78 f625 0x0320: f2ac ee14 0b54 020a 0262 07d0 fc02 0903 0x0330: fc08 e9c1 033f 083a 00ba 057b 0192 0500 0x0340: 025b 0334 060a ebdb f38c 0ac7 00aa 033d 0x0350: 034b 01d2 03b1 fedd 07bc f77e e6d4 00ba 0x0360: 03de fd2d 032b 0024 0563 00f0 031d 0407 0x0370: ea9f f21e fdad f97b 059b 005b 008f 0287 0x0380: fce7 06ba f6fc e614 0122 039e ff8b 05ba 0x0390: fea1 0378 00af 02d9 0611 ec6a f64b 0b1d 0x03a0: fedb 0397 0478 0356 0551 fb9a 07bc f925 0x03b0: e909 04a5 0401 0210 088b 00af 0496 000f 0x03c0: 04f6 0685 ebf9 f558 0a68 00f1 0380 03f1 0x03d0: 0304 0668 01c2 0996 f68f ea85 0640 0517 0x03e0: ffb7 0431 028a 0648 01d1 056f 04df eada 0x03f0: f8be 05a9 feba 078d 029e 0065 03b6 004e 0x0400: 0940 f69b eb28 07c1 0617 02a7 064b 02ff 0x0410: 0510 0145 0523 0469 ea1c f919 09b1 ffa4 0x0420: 0598 038f 04fd 04d6 ffe8 09aa f521 eb0d 0x0430: 07c8 0363 006f
09-28
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值