搞过Java线程的人都知道,stop这个方法是臭名昭著了,早就被弃用了,但是现在任然有很多钟情与他的人,永远都放不下他,因为从他的字面意思上我们可以知道他貌似可以停止一个线程,这个需求是每个搞线程开发的人都想要的操作,但是他并非是真正意义上的停止线程,而且停止线程还会引来一些其他的麻烦事,下面就来详细的介绍一下这个方法的历史:

从SUN的官方文档可以得知,调用Thread.stop()方法是不安全的,这是因为当调用Thread.stop()方法时,会发生下面两件事:

1. 即刻抛出ThreadDeath异常,在线程的run()方法内,任何一点都有可能抛出ThreadDeath Error,包括在catch或finally语句中。

2. 会释放该线程所持有的所有的锁,而这种释放是不可控制的,非预期的。

当线程抛出ThreadDeath异常时,会导致该线程的run()方法突然返回来达到停止该线程的目的。ThreadDetath异常可以在该线程run()方法的任意一个执行点抛出。但是,线程的stop()方法一经调用线程的run()方法就会即刻返回吗?

packagecom.threadstop.demo;

publicclassThreadStopTest {

publicstaticvoidmain(String[] args) {

try{

Thread t = newThread() {

//对于方法进行了同步操作,锁对象就是线程本身

publicsynchronizedvoidrun() {

try{

longstart=System.currentTimeMillis();

//开始计数

for(inti =0; i <100000; i++)

System.out.println("runing.."+ i);

System.out.println((System.currentTimeMillis()-start)+"ms");

} catch(Throwable ex) {

System.out.println("Caught in run: "+ ex);

ex.printStackTrace();

}

}

};

//开始计数

t.start();

//主线程休眠100ms

Thread.sleep(100);

//停止线程的运行

t.stop();

} catch(Throwable t) {

System.out.println("Caught in main: "+ t);

t.printStackTrace();

}

}

}

运行结果如下:

由于打印的数据太多了,就没有全部截图了,但是我们可以看到,调用了stop方法之后,线程并没有停止,而是将run方法执行完。那这个就诡异了,多次运行之后发现每次运行的结果都表明,工作线程并没有停止,而是每次都成功的数完数(执行完run方法),然后正常中止,而不是由stop()方法进行终止的。这个是为什么呢?根据SUN的文档,原则上只要一调用thread.stop()方法,那么线程就会立即停止,并抛出ThreadDeath error,查看了Thread的源代码后才发现,原先Thread.stop(Throwable

obj)方法是同步的,而我们工作线程的run()方法也是同步,那么这样会导致主线程和工作线程共同争用同一个锁(工作线程对象本身),由于工作线程在启动后就先获得了锁,所以无论如何,当主线程在调用t.stop()时,它必须要等到工作线程的run()方法执行结束后才能进行,结果导致了上述奇怪的现象。

下面看一下stop的源码:

@Deprecated

publicfinalvoidstop() {

stop(newThreadDeath());

}

再进到stop看:

@Deprecated

publicfinalsynchronizedvoidstop(Throwable obj) {

if(obj ==null)

thrownewNullPointerException();

SecurityManager security = System.getSecurityManager();

if(security !=null) {

checkAccess();

if((this!= Thread.currentThread()) ||

(!(obj instanceofThreadDeath))) {

security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);

}

}

// A zero status value corresponds to "NEW", it can't change to

// not-NEW because we hold the lock.

if(threadStatus !=0) {

resume(); // Wake up thread if it was suspended; no-op otherwise

}

// The VM can handle all thread states

stop0(obj);

}

stop0(obj)是一个native方法,我们看到stop方法是同步的,而这个同步的锁对象正好也是线程本身,所以造成上面的现象。

把上述工作线程的run()方法的同步去掉,再进行执行,结果就如上述第一点描述的那样了,运行结果如下:

从结果中我们可以看到,调用stop方法会抛出一个ThreadDeath异常,这时候run方法也就执行结束了,线程就终止了,这种是用抛异常来结束线程的,但是这种抛出线程是不安全的,因为他不可控制,不知道到在run方法中的何处就可能抛出异常,所以是危险的。下面在看一下stop的这个隐患可能造成的影响:

接下来是看看当调用thread.stop()时,被停止的线程会不会释放其所持有的锁,看如下代码:

publicstaticvoidmain(String[] args) {

//定义锁对象

finalObject lock =newObject();

//定义第一个线程,首先该线程拿到锁,而后等待3s,之后释放锁

try{

Thread t0 = newThread() {

publicvoidrun() {

try{

synchronized(lock) {

System.out.println("thread->"+ getName()  +" acquire lock.");

sleep(3*1000);

System.out.println("thread->"+ getName() +" 等待3s");

System.out.println("thread->"+ getName()  +" release lock.");

}

} catch(Throwable ex) {

System.out.println("Caught in run: "+ ex);

ex.printStackTrace();

}

}

};

//定义第二个线程,等待拿到锁对象

Thread t1 = newThread() {

publicvoidrun() {

synchronized(lock) {

System.out.println("thread->"+ getName()  +" acquire lock.");

}

}

};

//线程一先运行,先拿到lock

t0.start();

//而后主线程等待100ms,为了做延迟

Thread.sleep(100);

//停止线程一

//t0.stop();

//这时候在开启线程二

t1.start();

} catch(Throwable t) {

System.out.println("Caught in main: "+ t);

t.printStackTrace();

}

}

运行结果如下:

从运行结果中我们可以看到,当没有进行t0.stop()方法的调用时, 可以发现,两个线程争用锁的顺序是固定的。这个现象是正常的。

下面我们把t0.stop注释的哪行,删除注释,调用t0.stop()方法,运行结果如下:

从运行结果中我们可以看到,调用了t0.stop()方法后,可以发现,t0线程抛出了ThreadDeath error并且t0线程释放了它所占有的锁。

从上面的程序验证结果来看,thread.stop()确实是不安全的。它的不安全主要是:释放该线程所持有的所有的锁。一般任何进行加锁的代码块,都是为了保护数据的一致性,如果在调用thread.stop()后导致了该线程所持有的所有锁的突然释放(不可控制),那么被保护数据就有可能呈现不一致性,其他线程在使用这些被破坏的数据时,有可能导致一些很奇怪的应用程序错误。

下面顺便说一下:

Java中多线程锁释放的条件:

1)执行完同步代码块,就会释放锁。(synchronized)

2)在执行同步代码块的过程中,遇到异常而导致线程终止,锁也会被释放。(exception)

3)在执行同步代码块的过程中,执行了锁所属对象的wait()方法,这个线程会释放锁,进入对象的等待池。(wait)

从上面的三点我就可以看到stop方法释放锁是在第二点的,通过抛出异常来释放锁,通过证明,这种方式是不安全的,不可靠的。

好吧,Thread中的stop方法就说到这里了,后续还会有关Thread中的一些方法的详解,一定要关注奥!

java线程 stop()_Java中的线程Thread方法之---stop()相关推荐

  1. java多线程 线程安全_Java中的线程安全

    java多线程 线程安全 Thread Safety in Java is a very important topic. Java provides multi-threaded environme ...

  2. java 守护线程 作用_java中守护线程的一些概念和用法

    网上的资料中,守护线程的功能一般都是"只要当前JVM实例中尚存任何一个非守护线程没有结束,守护线程就全部工作:只有当最后一个非守护线程结束是,守护线程随着JVM一同结束工作,Daemon作用 ...

  3. java 全局变量线程安全_Java中的线程安全全局变量

    我试图了解 java中的线程安全机制,我需要一些帮助.我上课了: public class ThreadSafe { private Executor executor = new Scheduled ...

  4. java wait 参数_java中wait()和join()方法的区别是什么

    java中wait()和join()方法的区别是:存在不同的java包中:wait()方法用于线程间通信,它所施加的等待状态的线程可以被启动:join()方法用于在多个线程之间添加排序,它所施加的等待 ...

  5. java同步关键字_Java中synchronized关键字修饰方法同步的用法详解

    Java的最基本的同步方式,即使用synchronized关键字来控制一个方法的并发访问. 每一个用synchronized关键字声明的方法都是临界区.在Java中,同一个对象的临界区,在同一时间只有 ...

  6. java如何重写_java中如何重写一个方法

    方法的重写: 1.在子类中可以根据需要对从基类中继承来的方法进行重写. 2.重写的方法和被重写的方法必须具有相同方法名称.参数列表和返回类型. 3.重写方法不能使用比被重写的方法更严格的访问权限. 在 ...

  7. java.equal例子_Java中的== 和equals()方法详解与实例

    Java中的== 和equals()方法: Java中的数据类型,可分为两类: 1.基本数据类型,也称原始数据类型. byte,short,char,int,long,float,double,boo ...

  8. java 结束循环_java中结束循环的方法

    java中结束循环的方法 发布时间:2020-06-25 11:31:06 来源:亿速云 阅读:180 作者:Leah 这篇文章将为大家详细讲解有关java中结束循环的方法,小编觉得挺实用的,因此分享 ...

  9. Java实现暂停_Java中暂停线程的简单实现

    Java实现线程"暂停"和"继续"的功能.虽然suspend方法和resume方法已经过时,但是感觉实现起来比较方便.当然,前提是程序不是很复杂,不会出现死锁. ...

  10. java listfiles 使用_Java中list()和listFiles()方法之间的区别

    java.io包的名为File的类表示系统中的文件或目录(路径名).为了获得目录中所有现有文件的列表,此类提供了list()和ListFiles()方法. 它们之间的主要区别是该列表()方法返回一个字 ...

最新文章

  1. C语言中 指针强化训练之 memcpy
  2. php检测类是否存在,php判断类是否存在函数class_exists用法分析
  3. 一个filter引起的404错误
  4. vue+express 构建后台管理系统
  5. 走出囚徒困境的方法_囚徒困境的一种计算方法
  6. 【转】局部变量和全局变量---------------【答不对,你还敢说你精通、熟悉python?】...
  7. TeamViewer开机自启动实现在远程使用时重启远程计算机
  8. MAC安装Securecrt
  9. MES系统软件如何在数控加工车间应用?
  10. python人工智能教程百度云_【python实战教程百度网盘】求最新python人工智能视频教程网盘链接...
  11. 【毕业设计--开题报告】论文开题报告常见问题:参考论文格式,visio画箭头,wps段落设置
  12. 手机连接charles问题
  13. 百度地图API位置偏移的校准算法
  14. TryHackMe-NahamStore(常见web漏洞 大杂烩)
  15. 计算机卡住了怎样恢复,电脑经常死机,教您电脑经常死机怎么修复
  16. armv7与armv8 cp15 cache指令
  17. AcceptEx函数特点及需要提防的地方,看完了解更深入了,所以转过来
  18. android 自动设置时区,Android Things入门-设置本地时区
  19. c语言中什么是指针 什么是指针变量,C语言指针是什么?
  20. 高响应比优先算法实现进程调度模拟

热门文章

  1. DNS服务器地址查找不到,DNS服务器地址的查看方法
  2. Netplus里的基本概念
  3. 矩阵与行列式计算注意点
  4. 基于AdaBoost的人脸检测 含源码
  5. Linux下PHP下载安装
  6. discuz发帖流程_discuz 帖子模块用到的表及自动发帖函数
  7. QQ动态表情包如何制作 堪比沙漠骆驼gif
  8. ubuntu几款好用的代码编辑器
  9. Spring Security OAuth2搭建认证授权中心、资源服务中心、并结合网关校验的完整详细示例
  10. 如何安装SQL server 2005 开发版