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

来源:互联网 发布:人大 网络教育二学位 编辑:程序博客网 时间:2024/05/20 08:22

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() {@Overridepublic 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();// 启动线程t1for (int i = 0; i < 5; i++) {new Thread(myThread).start();// 启动线程}t1.stop();// 停止线程t1}}class MyThread implements Runnable {int a = 0;@Overridepublic 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 = 1Thread-5 :a = 1Thread-3 :a = 1Thread-2 :a = 1Thread-1 :a = 1

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

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

public class SafeStopThread extends Thread{private volatile boolean stop = false;@Overridepublic 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;@Overridepublic 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 = 0Thread-5 :a = 0Thread-4 :a = 0Thread-3 :a = 0Thread-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前后将线程的中断标志位打印出来,可以得出结论,该方法修改了线程的中断标志位。

 

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

 

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


 



 

原创粉丝点击