博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java如何合理的停掉一个线程
阅读量:5360 次
发布时间:2019-06-15

本文共 2784 字,大约阅读时间需要 9 分钟。

首先如果我们问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的其他概念原子性,可见性,有序性,有兴趣的朋友可以了解一下

以及volatile  

 

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

 

转载于:https://www.cnblogs.com/holdouts/articles/5896368.html

你可能感兴趣的文章
zoj 1232 Adventure of Super Mario
查看>>
组合数学 UVa 11538 Chess Queen
查看>>
oracle job
查看>>
Redis常用命令
查看>>
[转载]电脑小绝技
查看>>
windos系统定时执行批处理文件(bat文件)
查看>>
thinkphp如何实现伪静态
查看>>
BZOJ 2243: [SDOI2011]染色( 树链剖分 )
查看>>
BZOJ 1925: [Sdoi2010]地精部落( dp )
查看>>
c++中的string常用函数用法总结!
查看>>
[DLX精确覆盖+打表] hdu 2518 Dominoes
查看>>
SuperMap iServerJava 6R扩展领域开发及压力测试---判断点在那个面内(1)
查看>>
Week03-面向对象入门
查看>>
一个控制台程序,模拟机器人对话
查看>>
Vue 2.x + Webpack 3.x + Nodejs 多页面项目框架(上篇——纯前端多页面)
查看>>
我的PHP学习之路
查看>>
【题解】luogu p2340 奶牛会展
查看>>
对PostgreSQL的 SPI_prepare 的理解。
查看>>
解决响应式布局下兼容性的问题
查看>>
使用DBCP连接池对连接进行管理
查看>>