Java中的线程Thread方法之---stop()(一)

2014-11-24 02:25:23 · 作者: · 浏览: 2

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

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

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

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

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

[java]
  1. package com.threadstop.demo;
  2. public class ThreadStopTest {
  3. public static void main(String[] args) {
  4. try {
  5. Thread t = new Thread() {
  6. //对于方法进行了同步操作,锁对象就是线程本身
  7. public synchronized void run() {
  8. try {
  9. long start=System.currentTimeMillis();
  10. //开始计数
  11. for (int i = 0; i < 100000; i++)
  12. System.out.println(runing.. + i);
  13. System.out.println((System.currentTimeMillis()-start)+ms);
  14. } catch (Throwable ex) {
  15. System.out.println(Caught in run: + ex);
  16. ex.printStackTrace();
  17. }
  18. }
  19. };
  20. //开始计数
  21. t.start();
  22. //主线程休眠100ms
  23. Thread.sleep(100);
  24. //停止线程的运行
  25. t.stop();
  26. } catch (Throwable t) {
  27. System.out.println(Caught in main: + t);
  28. t.printStackTrace();
  29. }
  30. }
  31. } 运行结果如下:

    \

    由于打印的数据太多了,就没有全部截图了,但是我们可以看到,调用了stop方法之后,线程并没有停止,而是将run方法执行完。那这个就诡异了,多次运行之后发现每次运行的结果都表明,工作线程并没有停止,而是每次都成功的数完数(执行完run方法),然后正常中止,而不是由stop()方法进行终止的。这个是为什么呢?根据SUN的文档,原则上只要一调用thread.stop()方法,那么线程就会立即停止,并抛出ThreadDeath error,查看了Thread的源代码后才发现,原先Thread.stop(Throwable obj)方法是同步的,而我们工作线程的run()方法也是同步,那么这样会导致主线程和工作线程共同争用同一个锁(工作线程对象本身),由于工作线程在启动后就先获得了锁,所以无论如何,当主线程在调用t.stop()时,它必须要等到工作线程的run()方法执行结束后才能进行,结果导致了上述奇怪的现象。

    下面看一下stop的源码

    [java]
    1. @Deprecated
    2. public final void stop() {
    3. stop(new ThreadDeath());
    4. } 再进到stop看:

      [java]
      1. @Deprecated
      2. public final synchronized void stop(Throwable obj) {
      3. if (obj == null)
      4. throw new NullPointerException();
      5. SecurityManager security = System.getSecurityManager();
      6. if (security != null) {
      7. checkAccess();
      8. if ((this != Thread.currentThread()) ||
      9. (!(obj instanceof ThreadDeath))) {
      10. security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
      11. }
      12. }
      13. // A zero status value corresponds to NEW, it can't change to
      14. // not-NEW because we hold the lock.
      15. if (threadStatus != 0) {
      16. resume(); // Wake up thread if it was suspended; no-op otherwise
      17. }
      18. // The VM can handle all thread states
      19. stop0(obj);
      20. } stop0(obj)是一个native方法,我们看到stop方法是同步的,而这个同步的锁对象正好也是线程本身,所以造成上面的现象。

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

        \

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

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

        [java]
        1. public static void main(String[] args) {
        2. //定义锁对象
        3. final Object lock = new Object();
        4. //定义第一个线程,首先该线程拿到锁,而后等待3s,之后释放锁
        5. try {
        6. Thread t0 = new Thread() {
        7. public void run() {
        8. try {
        9. synchronized (lock) {
        10. System.out.println(thread-> + getName() + acquire lock.);
        11. sleep(3*1000);
        12. System.out.println(thread-> + getName() + 等待3s);
        13. System.out.println(thread-> + getName() + release lock.);
        14. }
        15. } catch (Throwable ex) {
        16. System.out.println(Caught in run: + ex);
        17. ex.printStackTrace();
        18. }
        19. }
        20. };
        21. //定义第二个线程,等待拿到锁对象
        22. Thread t1 = new Thread() {
        23. public void run() {
        24. synchronized (lock) {
        25. System.out.println(thread-> + getName() + acquire loc