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

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前后将线程的中断标志位打印出来,可以得出结论,该方法修改了线程的中断标志位。

 

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

 

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


 



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值