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前后将线程的中断标志位打印出来,可以得出结论,该方法修改了线程的中断标志位。
如果用什么遗漏,欢迎校正。
参考书籍:《编写高质量的代码》