在 Java 中安全地实现线程的暂停、恢复和停止操作需要避免使用已被废弃的 Thread.suspend()
、Thread.resume()
和 Thread.stop()
方法。这些方法会导致严重问题,如死锁、数据不一致和资源泄漏。以下是安全实现的推荐方案:
1. 安全停止线程
使用协作式的中断机制,让线程有机会清理资源后退出。
public class StoppableThread extends Thread {
private volatile boolean running = true; // volatile 保证可见性
@Override
public void run() {
try (Resource resource = acquireResource()) { // 使用 try-with-resources 自动清理
while (running && !Thread.currentThread().isInterrupted()) {
// 执行任务
processTask();
// 检查中断状态
if (Thread.interrupted()) {
break;
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢复中断状态
} finally {
cleanup(); // 最终清理
}
}
public void stopGracefully() {
running = false;
interrupt(); // 中断可能的阻塞状态
}
}
// 使用示例
StoppableThread thread = new StoppableThread();
thread.start();
Thread.sleep(5000);
thread.stopGracefully();
2. 安全暂停和恢复线程
使用 wait()
/notify()
机制实现可控的暂停/恢复。
public class PausableThread extends Thread {
private volatile boolean paused = false;
private final Object pauseLock = new Object(); // 专门用于暂停的锁对象
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
// 检查暂停状态
checkPaused();
// 执行任务
System.out.println("Working...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
private void checkPaused() {
synchronized (pauseLock) {
while (paused) {
try {
pauseLock.wait(); // 释放锁并等待
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}
}
public void pauseThread() {
paused = true;
}
public void resumeThread() {
synchronized (pauseLock) {
paused = false;
pauseLock.notifyAll(); // 唤醒所有等待线程
}
}
}
// 使用示例
PausableThread thread = new PausableThread();
thread.start();
// 暂停线程
Thread.sleep(3000);
thread.pauseThread();
System.out.println("Thread paused");
// 恢复线程
Thread.sleep(3000);
thread.resumeThread();
System.out.println("Thread resumed");
// 停止线程
Thread.sleep(3000);
thread.interrupt();
3. 使用高级并发工具
(1) 通过 Lock
和 Condition
实现更灵活的暂停
import java.util.concurrent.locks.*;
public class PausableTask implements Runnable {
private final Lock lock = new ReentrantLock();
private final Condition pauseCondition = lock.newCondition();
private boolean paused = false;
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
lock.lock();
try {
while (paused) {
pauseCondition.await(); // 等待恢复信号
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
} finally {
lock.unlock();
}
// 执行实际任务
doWork();
}
}
public void pause() {
lock.lock();
try {
paused = true;
} finally {
lock.unlock();
}
}
public void resume() {
lock.lock();
try {
paused = false;
pauseCondition.signalAll();
} finally {
lock.unlock();
}
}
}
(2) 使用 Future
控制任务执行
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = executor.submit(() -> {
while (!Thread.currentThread().isInterrupted()) {
// 执行任务
}
});
// 暂停(通过取消+重新提交实现)
future.cancel(true); // 中断任务
// ... 暂停一段时间 ...
future = executor.submit(task); // 重新提交
// 停止
future.cancel(true);
executor.shutdown();
4. 处理阻塞操作
对于 I/O 等不可中断的阻塞操作,需要特殊处理:
public class NetworkThread extends Thread {
private volatile ServerSocket serverSocket;
private volatile boolean running = true;
@Override
public void run() {
try (ServerSocket ss = new ServerSocket(8080)) {
this.serverSocket = ss;
while (running) {
Socket socket = ss.accept(); // 阻塞调用
process(socket);
}
} catch (IOException e) {
if (running) { // 非正常关闭时记录日志
e.printStackTrace();
}
}
}
public void stopGracefully() throws IOException {
running = false;
if (serverSocket != null) {
serverSocket.close(); // 强制解除 accept() 阻塞
}
}
}
关键原则与最佳实践
-
避免废弃方法
❌ 永远不要使用Thread.stop()
、Thread.suspend()
、Thread.resume()
-
使用协作式取消
- 通过标志位 + 中断请求
- 给线程清理资源的机会
-
确保资源释放
@Override public void run() { try (Connection conn = getConnection()) { while (running) { // 使用资源的操作 } } // 自动关闭连接 }
-
处理中断的正确方式
try { while (!Thread.interrupted()) { // 包含阻塞调用的工作 Thread.sleep(1000); } } catch (InterruptedException e) { // 收到中断信号时 Thread.currentThread().interrupt(); // 重置中断状态 }
-
暂停/恢复注意事项
- 避免在持有锁时暂停(可能导致死锁)
- 确保暂停状态可见(使用
volatile
) - 使用专用锁对象(避免与业务锁冲突)
-
监控线程状态
thread.addObserver((o, arg) -> { if (thread.getState() == State.WAITING) { logger.info("Thread paused"); } });
不同操作的推荐实现
操作 | 安全实现方案 | 风险点 |
---|---|---|
停止 | 标志位 + interrupt() | 阻塞操作无法立即响应 |
暂停 | wait() /notify() 或 Condition | 在同步块中暂停可能导致死锁 |
恢复 | notify() /signal() 唤醒 | 确保恢复信号可见 |
架构建议
通过遵循这些原则和模式,可以实现线程的完全控制而不会引发并发问题。对于复杂场景,建议使用 java.util.concurrent
包中的高级工具(如 ExecutorService
、Future
)来管理线程生命周期。