线程的最佳实践二:不使用stop方法停止线程

本文探讨了Java中线程终止的问题,分析了Thread类stop方法的缺陷,并提供了一种使用volatile变量来安全停止线程的方法。

1.线程启动完毕后,在运行一段时间后可能需要终止,而java的api终止线程只提供了stop方法。但是:

A.stop方法是过时的@Deprecated。
B.stop方法会导致代码逻辑不完整。
C.stop方法破坏原子逻辑。

2.stop方法破坏代码逻辑事例,代码如下:

public class Test {

	public static void main(String[] args) throws InterruptedException {
		Thread thread = new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					Thread.sleep(1000);// 子线程休眠1秒
				} catch (InterruptedException e) {
					// 异常处理
				}
				System.out.println("业务逻辑");// 业务逻辑处理,资源关闭等
			}
		});

		thread.start();// 启动线程

		Thread.sleep(100);// 主线程休眠0.1秒
		System.out.println("其他");
		thread.stop();// 停止子线程
	}

}

如代码那样,如果对子线程调用了stop方法,我们的子线程业务逻辑就没有办法完成了,如果业务逻辑中包含像资源回收,情景初始化等,这样就很危险了,而且这种操作很具有隐蔽性,子线程执行到何处会被关闭很难定位,会为以后的维护带来很多麻烦。

3.stop方法会丢弃所有的锁,从而破环原子逻辑,事例代码如下:

public class Test {

	public static void main(String[] args) throws InterruptedException {
		MyThread myThread = new MyThread();
		Thread t1 = new Thread(myThread);
		t1.start();// 启动线程t1
		for (int i = 0; i < 5; i++) {
			new Thread(myThread).start();// 启动线程
		}
		t1.stop();// 停止线程t1

	}

}

class MyThread implements Runnable {

	int a = 0;

	@Override
	public void run() {
		sync();
	}

	private synchronized void sync() {
		a++;
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			// TODO
		}
		a--;
		System.out.println(Thread.currentThread().getName() + " :a = " + a);

	}
}
输出结果:
Thread-4 :a = 1
Thread-5 :a = 1
Thread-3 :a = 1
Thread-2 :a = 1
Thread-1 :a = 1

MyThread实现了Runnable接口,其中run方法中调研了一个synchronized方法,表示该方法内部是原子逻辑。那么打印出来的应该都是a=0,但是如果一个正在执行的线程被stop了,就会破坏这种原子逻辑,如结果输出那样。

4.如何停止线程呢?答案也很简单,使用一个volatile变量作为标志位。事例代码如下:

public class SafeStopThread extends Thread{
	
	private volatile boolean stop = false;
	
	@Override
	public void run(){
		while(!stop){//判断线程是否运行
			//Do something
		}
	}
	
	public void terminate(){
		stop = true;
	}

}

在线程体中判断是否需要停止运行,即可保证线程体的逻辑完整性,也不会破坏原子逻辑。综合3,4给出事例代码如下:

public class Test {
	
	public static void main(String[] args) throws InterruptedException {
		SafeStopThread1 safeStopThread = new SafeStopThread1();
		Thread t1 = new Thread(safeStopThread);
		t1.start();
		for(int i=0;i<5;i++){
		new Thread(safeStopThread).start();// 启动线程
		}
		safeStopThread.terminate();
		
	}

}

class SafeStopThread extends Thread{
//安全停止线程	
	private volatile boolean stop = false;
	int a = 0;
	@Override
	public void run(){
		while(!stop){//判断线程是否运行
			sync();
		}
	}
	
	public void terminate(){
		stop = true;
	}
	
	
	private synchronized void sync(){
		a++;
		try{
			Thread.sleep(100);
		}catch(InterruptedException e){
			//TODO
		}
		a--;
		System.out.println(Thread.currentThread().getName()+" :a = "+a);
	}
}

输出结果为:

Thread-1 :a = 0
Thread-5 :a = 0
Thread-4 :a = 0
Thread-3 :a = 0
Thread-2 :a = 0

5.补充

Thread类的interrupt方法,看上去好像是一个终止线程的方法,但是它不能终止一个正在执行着的线程,它只是修改中断标志而已。代码如下:

public class ThreadInterrupt {

	public static void main(String[] args) {
		Thread thread = new Thread(){
			public void run(){
				while(true){
					System.out.println("Running....");
				}
			}
		};
		
		thread.start();
		
		//System.out.println(thread.isInterrupted());
		
		thread.interrupt();//修改线程中断的标志位

		//System.out.println(thread.isInterrupted());
		

	}

}

这段程序会一直输出Running......足以说明interrupt方法不能终止一个线程,如果在interrupt前后将线程的中断标志位打印出来,可以得出结论,该方法修改了线程的中断标志位。

 

如果用什么遗漏,欢迎校正。

 

参考书籍:《编写高质量的代码》


 



 

<think>我们被要求回答:线程停止使用什么方法,为什么推荐使用stop方法 首先,回答线程停止的正确方法: 在Java中,停止线程的正确方法使用已废弃的stop()方法,而是通过让线程执行完run()方法自然结束,或者通过设置一个标志位(如volatile boolean)来通知线程应该退出。另外,可以使用中断机制(interrupt)来请求线程停止。 然后,解释为什么推荐使用stop方法stop()方法被废弃是因为它是安全的,它会强行终止线程,可能导致以下问题: 1. 释放所有锁:stop()会释放该线程持有的所有锁,可能导致对象状态一致。 2. 破坏数据:如果线程正在操作共享数据,突然终止可能导致数据处于一致状态。 3. 可预知的行为:由于突然终止,程序可能表现出可预知的行为。 最后,给出相关代码示例: 展示如何通过标志位和中断机制来停止线程。 按照要求,最后提出四个相关问题。</think>### Java线程停止的正确方法及`stop()`的废弃原因 #### 正确停止线程方法 1. **标志位中断法(推荐)** ```java public class SafeStopThread implements Runnable { // 使用volatile保证可见性 private volatile boolean running = true; @Override public void run() { while (running) { try { // 执行任务 Thread.sleep(1000); System.out.println("Working..."); } catch (InterruptedException e) { // 响应中断请求 Thread.currentThread().interrupt(); break; } } System.out.println("Thread stopped safely"); } // 安全停止方法 public void stop() { running = false; } } // 使用示例 SafeStopThread task = new SafeStopThread(); Thread thread = new Thread(task); thread.start(); // 安全停止线程 Thread.sleep(5000); task.stop(); ``` 2. **中断机制(标准API)** ```java Thread worker = new Thread(() -> { while (!Thread.currentThread().isInterrupted()) { try { System.out.println("Processing data..."); Thread.sleep(1000); } catch (InterruptedException e) { // 收到中断信号,退出循环 Thread.currentThread().interrupt(); System.out.println("Thread interrupted"); break; } } }); worker.start(); // 请求中断 Thread.sleep(3000); worker.interrupt(); ``` 3. **ExecutorService关闭** ```java ExecutorService executor = Executors.newSingleThreadExecutor(); executor.submit(() -> { while (!Thread.interrupted()) { System.out.println("Task running"); } }); // 优雅关闭 executor.shutdown(); try { if (!executor.awaitTermination(5, TimeUnit.SECONDS)) { executor.shutdownNow(); // 强制中断 } } catch (InterruptedException e) { executor.shutdownNow(); } ``` --- ### 为什么废弃`Thread.stop()`方法 #### 根本原因 `stop()`方法会**强制终止线程**而考虑其当前状态,导致以下严重问题: #### 1. 对象状态损坏 ```java class BankAccount { private int balance = 1000; public synchronized void transfer(int amount) { int newBalance = balance + amount; // 在计算和执行之间被stop()中断 balance = newBalance; // 可能只执行了一半 } } ``` - **问题**:如果`stop()`在`balance = newBalance`执行前调用,账户状态将处于一致状态 - **后果**:数据完整性被破坏,可能导致资金计算错误 #### 2. 锁资源泄漏 ```java public void processResource() { synchronized(lock) { // 获取锁后执行操作 doCriticalOperation(); // 如果在此处被stop(),锁永远会释放 } } ``` - **问题**:`stop()`会释放线程持有的所有锁,但会执行锁保护区域的清理代码 - **后果**:其他线程可能看到部分修改的共享数据 #### 3. 资源泄漏风险 ```java public void fileOperation() { FileOutputStream fos = new FileOutputStream("data.bin"); fos.write(data); // 在此处被stop() // fos.close() 永远会执行 } ``` - **问题**:文件句柄、数据库连接等资源无法正常关闭 - **后果**:资源泄漏最终导致系统崩溃 #### 4. `ThreadDeath`异常传播 ```java public void nestedMethod() { try { innerMethod(); } catch (ThreadDeath td) { // 无法正确处理此异常 throw td; } } ``` - **问题**:`stop()`会抛出`ThreadDeath`异常,可能被任意catch块捕获 - **后果**:破坏正常的异常处理流程 --- ### 官方声明(Java文档) > "This method is inherently unsafe. Stopping a thread with Thread.stop causes it to unlock all of the monitors that it has locked... If any of the objects previously protected by these monitors were in an inconsistent state, the damaged objects become visible to other threads, potentially leading to arbitrary behavior." --- ### 最佳实践总结 | **方法** | **适用场景** | **优点** | **缺点** | |------------------------|--------------------------------|----------------------------------|-----------------------| | 标志位中断 | 简单循环任务 | 实现简单,可控性强 | 需主动检查标志位 | | `interrupt()`机制 | 阻塞操作(IO/sleep/wait) | 标准API,可响应阻塞状态 | 需正确处理中断异常 | | `ExecutorService`关闭 | 线程池管理 | 提供优雅关闭和超时控制 | 仅适用于线程池 | | 守护线程 | 后台服务 | 随JVM退出自动终止 | 能控制精确停止时机 | --- ### 正确处理中断的模板 ```java public void run() { try { while (!Thread.currentThread().isInterrupted()) { // 执行任务 performTask(); // 阻塞操作需处理InterruptedException try { TimeUnit.MILLISECONDS.sleep(100); } catch (InterruptedException e) { // 恢复中断状态并退出 Thread.currentThread().interrupt(); } } } finally { // 保证资源清理 cleanupResources(); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值