* If there is a security manager installed, its checkAccess
* method is called with this
* as its argument. This may result in a
* SecurityException
being raised (in the current thread).
*
* If this thread is different from the current thread (that is, the current
* thread is trying to stop a thread other than itself), the
* security manager's checkPermission
method (with a
* RuntimePermission("stopThread")
argument) is called in
* addition.
* Again, this may result in throwing a
* SecurityException
(in the current thread).
*
* The thread represented by this thread is forced to stop whatever
* it is doing abnormally and to throw a newly created
* ThreadDeath
object as an exception.
*
* It is permitted to stop a thread that has not yet been started. * If the thread is eventually started, it immediately terminates. *
* An application should not normally try to catch
* ThreadDeath
unless it must do some extraordinary
* cleanup operation (note that the throwing of
* ThreadDeath
causes finally
clauses of
* try
statements to be executed before the thread
* officially dies). If a catch
clause catches a
* ThreadDeath
object, it is important to rethrow the
* object so that the thread actually dies.
*
* The top-level error handler that reacts to otherwise uncaught
* exceptions does not print out a message or otherwise notify the
* application if the uncaught exception is an instance of
* ThreadDeath
.
*
* @exception SecurityException if the current thread cannot
* modify this thread.
* @see #interrupt()
* @see #checkAccess()
* @see #run()
* @see #start()
* @see ThreadDeath
* @see ThreadGroup#uncaughtException(Thread,Throwable)
* @see SecurityManager#checkAccess(Thread)
* @see SecurityManager#checkPermission
* @deprecated This method is inherently unsafe. Stopping a thread with
* Thread.stop causes it to unlock all of the monitors that it
* has locked (as a natural consequence of the unchecked
* ThreadDeath
exception propagating up the stack). If
* any of the objects previously protected by these monitors were in
* an inconsistent state, the damaged objects become visible to
* other threads, potentially resulting in arbitrary behavior. Many
* uses of stop
should be replaced by code that simply
* modifies some variable to indicate that the target thread should
* stop running. The target thread should check this variable
* regularly, and return from its run method in an orderly fashion
* if the variable indicates that it is to stop running. If the
* target thread waits for long periods (on a condition variable,
* for example), the interrupt
method should be used to
* interrupt the wait.
* For more information, see
* Why
* are Thread.stop, Thread.suspend and Thread.resume Deprecated?.
*/
@Deprecated
public final void stop() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
checkAccess();
if (this != Thread.currentThread()) {
security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
}
}
// A zero status value corresponds to "NEW", it can't change to
// not-NEW because we hold the lock.
if (threadStatus != 0) {
resume(); // Wake up thread if it was suspended; no-op otherwise
}
// The VM can handle all thread states
stop0(new ThreadDeath());
}
```
可以看出 `stop()` 方法被 `@Deprecated` 注释修饰了,而被此注解修饰的代码表示为过时方法,不建议被使用。从 `stop()` 的备注信息可以看出,官方也不建议使用 `stop()` ,说它是一个非安全的方法。
## 正确终止线程
那如何终止线程呢?这里提供 2 个正确的方法:
1. 设置退出标识退出线程;
1. 使用 `interrupt()` 方法终止线程。
### 1.自定义退出标识
我们可以自定义一个布尔变量来标识是否需要退出线程,实现代码如下:
```java
// 自定义退出标识退出线程
static class FlagThread extends Thread {
public volatile boolean exit = false;
public void run() {
while (!exit) {
// 执行正常的业务逻辑
}
}
}
```
可以看出我们使用了关键字 `volatile` 对线程进行了修饰,这样就可以保证多线程的执行安全了,在我们需要让线程退出时,只需要把变量 `exit` 赋值为 `true` 就可以了。
### 2.interrupt 终止线程
当我们使用 `interrupt()` 方法时,以上两个示例的执行结果就正常了,执行代码如下:
```java
public class ThreadStopExample {
public static void main(String[] args) throws InterruptedException {
// 问题一:破坏了程序的完整性
Thread t1 = new Thread(() -> {
try {
System.out.println("子线程开始执行");
// 模拟业务处理
Thread.sleep(1000);
} catch (Exception e) { }
// 伪代码:重要业务方法
System.out.println("子线程的重要业务方法");
});
t1.start();
// 让子线程先运行一点业务
Thread.sleep(100);
// 终止子线程
t1.interrupt();
// 等待一段时间,确保子线程“执行完”
Thread.sleep(3000);
System.out.println("主线程执行完成");
// 问题二:破坏了原子逻辑
MyThread myThread = new MyThread();
Thread t2 = new Thread(myThread);
// 开启线程
t2.start();
for (int i = 0; i < 10; i++) {
Thread t = new Thread(myThread);
t.start();
}
// 结束线程
t2.interrupt();
}
/**
* 自定义原子测试线程
*/
static class MyThread implements Runnable {
// 计数器
int num = 0;
@Override
public void run() {
// 同步代码块,保证原子操作
synchronized (MyThread.class) {
// 自增
num++;
try {
// 线程休眠 0.1 秒
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
// 自减
num--;
System.out.println(Thread.currentThread().getName() + " | num=" + num);
}
}
}
}
```
以上程序的执行结果为:
> 子线程开始执行
>
> 子线程的重要业务方法
>
> 主线程执行完成
>
> sleep interrupted
>
> Thread-1 | num=0
>
> Thread-9 | num=0
>
> Thread-10 | num=0
>
> Thread-7 | num=0
>
> Thread-6 | num=0
>
> Thread-5 | num=0
>
> Thread-4 | num=0
>
> Thread-2 | num=0
>
> Thread-3 | num=0
>
> Thread-11 | num=0
>
> Thread-8 | num=0
>
可以看出以上的执行都符合我们的预期,这才是正确的终止线程的方式。
## 总结
本文我们讲了线程的三种终止方式,自定义退出标识的方式、使用 `stop()` 的方式或 `interrupt()` 的方式。其中 `stop()` 的方式会导致程序的完整性和原子性被破坏的问题,并且此方法被 JDK 标识为过期方法,不建议使用,而 `interrupt()` 方法无疑是最适合我们的终止线程的方式。