java如何合理的停掉一个线程

首先如果我们问java如何去停掉一个线程,大家肯定会说stop嘛,但是也有一些朋友提出质疑,stop安全吗?

没错stop是不提倡的,

不提倡的stop()方法 
臭名昭著的stop()停止线程的方法已不提倡使用了,原因是什么呢?
 当在一个线程对象上调用stop()方法时,这个线程对象所运行的线程就会立即停止,并抛出特殊的ThreadDeath()异常。这里的“立即”因为太“立即”了,
假如一个线程正在执行:

synchronized void {
 x = 3;
 y = 4;
}

  由于方法是同步的,多个线程访问时总能保证x,y被同时赋值,而如果一个线程正在执行到x = 3;时,被调用了 stop()方法,即使在同步块中,它也干脆地stop了,这样就产生了不完整的残废数据。而多线程编程中最最基础的条件要保证数据的完整性,所以请忘记 线程的stop方法,以后我们再也不要说“停止线程”了。

   如何才能“结束”一个线程?

那么什么方式才是我们提倡的呢,用interrupt()?

那么如何能确保线程真正停止?在线程同步的时候我们有一个叫“二次惰性检测”(double check),能在提高效率的基础上又确保线程真正中同步控制中。那么我把线程正确退出的方法称为“双重安全退出”,即不以isInterrupted ()为循环条件。而以一个标记作为循环条件:

  1. package org.leadfar;  
  2.  
  3.  
  4. public class MyThread04 extends Thread {  
  5.       
  6.     private boolean stop = false;  
  7.     public MyThread04(String threadName) {  
  8.         super(threadName);  
  9.     }  
  10.  
  11.     @Override 
  12.     public void run() {  
  13.           
  14.         for (int j = 0; j < 100; j++) {  
  15.             if(this.isInterrupted()) break;  
  16.             System.out.println(Thread.currentThread().getName()+":"+j);  
  17.             try {  
  18.                 Thread.sleep(1000);  
  19.             } catch (InterruptedException e) {  
  20.                 e.printStackTrace();  
  21.             }  
  22.         }  
  23.           
  24.     }  
  25.       
  26.     public void setStop() {  
  27.         this.stop = true;  
  28.     }  
  29.  
  30.     //第一个线程  
  31.     public static void main(String[] args) {  
  32.         MyThread04 t = new MyThread04("辅线程");  
  33.         t.start();  
  34.           
  35.         for (int i = 0; i < 10; i++) {  
  36.             System.out.println(Thread.currentThread().getName()+":"+i);  
  37.         }  
  38.         System.out.println("....................");  
  39.         t.interrupt();  
  40.           
  41.     }  
  42. }

 但这个很可能不会终止线程,因为当我们终止这个线程时很可能就会发生InterruptedException异常,当有这个异常发生时我们设置的终断状态也会被清除,所以我们要终断某个线程应采用以下这个方法:

  1. package org.leadfar;  
  2.  
  3.  
  4. public class MyThread04 extends Thread {  
  5.       
  6.     private boolean stop = false;  
  7.     public MyThread04(String threadName) {  
  8.         super(threadName);  
  9.     }  
  10.  
  11.     @Override 
  12.     public void run() {  
  13.           
  14.         for (int j = 0; j < 100; j++) {  
  15.             if(stop) break;  
  16.             System.out.println(Thread.currentThread().getName()+":"+j);  
  17.             try {  
  18.                 Thread.sleep(1000);  
  19.             } catch (InterruptedException e) {  
  20.                 e.printStackTrace();  
  21.             }  
  22.         }  
  23.           
  24.     }  
  25.       
  26.     public void setStop() {  
  27.         this.stop = true;  
  28.     }  
  29.  
  30.     //第一个线程  
  31.     public static void main(String[] args) {  
  32.         MyThread04 t = new MyThread04("辅线程");  
  33.         t.start();  
  34.           
  35.         for (int i = 0; i < 10; i++) {  
  36.             System.out.println(Thread.currentThread().getName()+":"+i);  
  37.         }  
  38.         System.out.println("....................");  
  39.         t.setStop();  
  40.     }  
  41. }  

  通过设置一个我们自己的标识来达到终端某个线程。

 

讲到这里大家一定就认为这样一定没有问题了对吗,答案是不,

其实大家可以想想我们设置的那个stop变量一定会很老实的被我们修改吗,想想一个简单的例子

//线程1
boolean stop = false;
while(!stop){
    doSomething();
}
 
//线程2
stop = true;

   这段代码是很典型的一段代码,很多人在中断线程时可能都会采用这种标记办法。但是事实上,这段代码会完全运行正确么?即一定会将线程中断么?不一定,也许在大多数时候,这个代码能够把线程中断,但是也有可能会导致无法中断线程(虽然这个可能性很小,但是只要一旦发生这种情况就会造成死循环了)。

  下面解释一下这段代码为何有可能导致无法中断线程。在前面已经解释过,每个线程在运行过程中都有自己的工作内存,那么线程1在运行的时候,会将stop变量的值拷贝一份放在自己的工作内存当中。

  那么当线程2更改了stop变量的值之后,但是还没来得及写入主存当中,线程2转去做其他事情了,那么线程1由于不知道线程2对stop变量的更改,因此还会一直循环下去。

所以在这里我们引入了一个关键字volatile,其实这里还有一些java的其他概念原子性,可见性,有序性,有兴趣的朋友可以了解一下

http://www.cnblogs.com/dolphin0520/p/3920373.html

以及volatile  

 http://www.cnblogs.com/yakun/p/3589437.html

好的那么我们的线程到底怎么才能被我们停掉,相比大家也能感觉到我们可以在stop关键词上加上volatile关键字啊,没错就是这样的方式。其实我们在终止线程的时候有很多复杂的情况,这里就不一一列举了。

 

posted @ 2016-09-22 14:56 奋斗,坚持 阅读(...) 评论(...) 编辑 收藏