Java知多少(65)线程的挂起、恢复和终止

有时,线程的挂起是很有用的。例如,一个独立的线程可以用来显示当日的时间。如果用户不希望用时钟,线程被挂起。在任何情形下,挂起线程是很简单的,一旦挂起,重新启动线程也是一件简单的事。

挂起,终止和恢复线程机制在Java 2和早期版本中有所不同。尽管你运用Java 2的途径编写代码,你仍需了解这些操作在早期Java环境下是如何完成的。例如,你也许需要更新或维护老的代码。你也需要了解为什么Java 2会有这样的变化。因为这些原因,下面内容描述了执行线程控制的原始方法,接着是Java 2的方法。

Java 1.1或更早版本的线程的挂起、恢复和终止

先于Java2的版本,程序用Thread 定义的suspend() 和 resume() 来暂停和再启动线程。它们的形式如下:
    final void suspend( )
    final void resume( )
下面的程序描述了这些方法:

 1 // Using suspend() and resume().
 2 class NewThread implements Runnable {
 3     String name; // name of thread
 4     Thread t;
 5     NewThread(String threadname) {
 6         name = threadname;
 7         t = new Thread(this, name);
 8         System.out.println("New thread: " + t);
 9         t.start(); // Start the thread
10     }
11     // This is the entry point for thread.
12     public void run() {
13         try {
14             for(int i = 15; i > 0; i--) {
15                 System.out.println(name + ": " + i);
16                 Thread.sleep(200);
17             }
18         } catch (InterruptedException e) {
19             System.out.println(name + " interrupted.");
20         }
21         System.out.println(name + " exiting.");
22     }
23 }
24 class SuspendResume {
25     public static void main(String args[]) {
26         NewThread ob1 = new NewThread("One");
27         NewThread ob2 = new NewThread("Two");
28         try {
29             Thread.sleep(1000);
30             ob1.t.suspend();
31             System.out.println("Suspending thread One");
32             Thread.sleep(1000);
33             ob1.t.resume();
34             System.out.println("Resuming thread One");
35             ob2.t.suspend();
36             System.out.println("Suspending thread Two");
37             Thread.sleep(1000);
38             ob2.t.resume();
39             System.out.println("Resuming thread Two");
40         } catch (InterruptedException e) {
41             System.out.println("Main thread Interrupted");
42         }
43         // wait for threads to finish
44         try {
45             System.out.println("Waiting for threads to finish.");
46             ob1.t.join();
47             ob2.t.join();
48         } catch (InterruptedException e) {
49             System.out.println("Main thread Interrupted");
50         }
51         System.out.println("Main thread exiting.");
52     }
53 }

程序的部分输出如下:

 1 New thread: Thread[One,5,main]
 2 One: 15
 3 New thread: Thread[Two,5,main]
 4 Two: 15
 5 One: 14
 6 Two: 14
 7 One: 13
 8 Two: 13
 9 One: 12
10 Two: 12
11 One: 11
12 Two: 11
13 Suspending thread One
14 Two: 10
15 Two: 9
16 Two: 8
17 Two: 7
18 Two: 6
19 Resuming thread One
20 Suspending thread Two
21 One: 10
22 One: 9
23 One: 8
24 One: 7
25 One: 6
26 Resuming thread Two
27 Waiting for threads to finish.
28 Two: 5
29 One: 5
30 Two: 4
31 One: 4
32 Two: 3
33 One: 3
34 Two: 2
35 One: 2
36 Two: 1
37 One: 1
38 Two exiting.
39 One exiting.
40 Main thread exiting.

Thread类同样定义了stop() 来终止线程。它的形式如下:

void stop( )
一旦线程被终止,它不能被resume() 恢复继续运行。

Java 2中挂起、恢复和终止线程

Thread定义的suspend(),resume()和stop()方法看起来是管理线程的完美的和方便的方法,它们不能用于新Java版本的程序。下面是其中的原因。Thread类的suspend()方法在Java2中不被赞成,因为suspend()有时会造成严重的系统故障。假定对关键的数据结构的一个线程被锁定的情况,如果该线程在那里挂起,这些锁定的线程并没有放弃对资源的控制。其他的等待这些资源的线程可能死锁。

Resume()方法同样不被赞同。它不引起问题,但不能离开suspend()方法而独立使用。Thread类的stop()方法同样在Java 2中受到反对。这是因为该方法可能导致严重的系统故障。设想一个线程正在写一个精密的重要的数据结构且仅完成一个零头。如果该线程在此刻终止,则数据结构可能会停留在崩溃状态。

因为在Java 2中不能使用suspend(),resume()和stop() 方法来控制线程,你也许会想那就没有办法来停止,恢复和结束线程。其实不然。相反,线程必须被设计以使run() 方法定期检查以来判定线程是否应该被挂起,恢复或终止它自己的执行。有代表性的,这由建立一个指示线程状态的标志变量来完成。只要该标志设为“running”,run()方法必须继续让线程执行。如果标志为“suspend”,线程必须暂停。若设为“stop”,线程必须终止。

当然,编写这样的代码有很多方法,但中心主题对所有的程序应该是相同的。

下面的例题阐述了从Object继承的wait()和notify()方法怎样控制线程的执行。该例与前面讲过的程序很像。然而,不被赞同的方法都没有用到。让我们思考程序的执行。

NewTread 类包含了用来控制线程执行的布尔型的实例变量suspendFlag。它被构造函数初始化为false。Run()方法包含一个监测suspendFlag 的同步声明的块。如果变量是true,wait()方法被调用以挂起线程。Mysuspend()方法设置suspendFlag为true。Myresume()方法设置suspendFlag为false并且调用notify()方法来唤起线程。最后,main()方法被修改以调用mysuspend()和myresume()方法。

 1 // Suspending and resuming a thread for Java2
 2 class NewThread implements Runnable {
 3     String name; // name of thread
 4     Thread t;
 5     boolean suspendFlag;
 6     NewThread(String threadname) {
 7         name = threadname;
 8         t = new Thread(this, name);
 9         System.out.println("New thread: " + t);
10         suspendFlag = false;
11         t.start(); // Start the thread
12     }
13     // This is the entry point for thread.
14     public void run() {
15         try {
16             for(int i = 15; i > 0; i--) {
17                 System.out.println(name + ": " + i);
18                 Thread.sleep(200);
19                 synchronized(this) {
20                     while(suspendFlag) {
21                         wait();
22                     }
23                 }
24             }
25         } catch (InterruptedException e) {
26             System.out.println(name + " interrupted.");
27         }
28         System.out.println(name + " exiting.");
29     }
30     void mysuspend() {
31         suspendFlag = true;
32     }
33     synchronized void myresume() {
34         suspendFlag = false;
35         notify();
36     }
37 }
38 class SuspendResume {
39     public static void main(String args[]) {
40        NewThread ob1 = new NewThread("One");
41        NewThread ob2 = new NewThread("Two");
42        try {
43           Thread.sleep(1000);
44           ob1.mysuspend();
45           System.out.println("Suspending thread One");
46           Thread.sleep(1000);
47           ob1.myresume();
48           System.out.println("Resuming thread One");
49           ob2.mysuspend();
50           System.out.println("Suspending thread Two");
51           Thread.sleep(1000);
52           ob2.myresume();
53           System.out.println("Resuming thread Two");
54        } catch (InterruptedException e) {
55           System.out.println("Main thread Interrupted");
56        }
57        // wait for threads to finish
58        try {
59           System.out.println("Waiting for threads to finish.");
60           ob1.t.join();
61           ob2.t.join();
62        } catch (InterruptedException e) {
63            System.out.println("Main thread Interrupted");
64        }
65        System.out.println("Main thread exiting.");
66     }
67 }

该程序的输出与前面的程序相同。此书的后面部分,你将看到用Java 2机制控制线程的更多例子。尽管这种机制不像老方法那样“干净”,然而,它是确保运行时不发生错误的方法。它是所有新的代码必须采用的方法。

系列文章:

Java知多少(上)

Java知多少(39)interface接口

Java知多少(40)接口和抽象类的区别

Java知多少(41)泛型详解

Java知多少(42)泛型通配符和类型参数的范围

Java知多少(43)异常处理基础

Java知多少(44)异常类型

Java知多少(45)未被捕获的异常

Java知多少(46)try和catch的使用

Java知多少(47)多重catch语句的使用

Java知多少(48)try语句的嵌套

Java知多少(49)throw:异常的抛出

Java知多少(50)Java throws子句

Java知多少(51)finally

Java知多少(52)内置异常

Java知多少(53)使用Java创建自己的异常子类

Java知多少(54)断言详解

Java知多少(55)线程

Java知多少(56)线程模型

Java知多少(57)主线程

Java知多少(58)线程Runnable接口和Thread类详解

Java知多少(59)创建多线程

Java知多少(60)isAlive()和join()的使用

Java知多少(61)线程优先级

Java知多少(62)线程同步

Java知多少(63)线程间通信

Java知多少(64)线程死锁

时间: 2024-11-08 10:25:53

Java知多少(65)线程的挂起、恢复和终止的相关文章

Java并发学习之五——线程的睡眠和恢复

本文是学习网络上的文章时的总结,感谢大家无私的分享. 1.Thread类的sleep方法,可以使线程睡眠.此方法接收一个整数作为参数,表示线程暂停运行的毫秒数.在调用sleep方法后,当时间结束时,JVM会安排他们CPU时间,线程会继续按指令执行. 另一种可能是使用一个有TimeUnit列举元素的sleep方法,使用线程类的sleep方法让当前线程睡眠,但是它接收的参数单位后会转成毫秒的. 2.当你调用sleep()方法,Thread离开CPU并在一段时间内停止运行.在这段时间内,他是不消耗CP

Java知多少(57)主线程

当Java程序启动时,一个线程立刻运行,该线程通常叫做程序的主线程(main thread),因为它是程序开始时就执行的.主线程的重要性体现在两方面: 它是产生其他子线程的线程: 通常它必须最后完成执行,因为它执行各种关闭动作. 尽管主线程在程序启动时自动创建,但它可以由一个Thread对象控制.为此,你必须调用方法currentThread()获得它的一个引用,currentThread()是Thread类的公有的静态成员.它的通常形式如下:    static Thread currentT

Java知多少(63)线程间通信

上述例题无条件的阻塞了其他线程异步访问某个方法.Java对象中隐式管程的应用是很强大的,但是你可以通过进程间通信达到更微妙的境界.这在Java中是尤为简单的. 像前面所讨论过的,多线程通过把任务分成离散的和合乎逻辑的单元代替了事件循环程序.线程还有第二优点:它远离了轮询.轮询通常由重复监测条件的循环实现.一旦条件成立,就要采取适当的行动.这浪费了CPU时间.举例来说,考虑经典的序列问题,当一个线程正在产生数据而另一个程序正在消费它.为使问题变得更有趣,假设数据产生器必须等待消费者完成工作才能产生

Java知多少(62)线程同步

当两个或两个以上的线程需要共享资源,它们需要某种方法来确定资源在某一刻仅被一个线程占用.达到此目的的过程叫做同步(synchronization).像你所看到的,Java为此提供了独特的,语言水平上的支持. 同步的关键是管程(也叫信号量semaphore)的概念.管程是一个互斥独占锁定的对象,或称互斥体(mutex).在给定的时间,仅有一个线程可以获得管程.当一个线程需要锁定,它必须进入管程.所有其他的试图进入已经锁定的管程的线程必须挂起直到第一个线程退出管程.这些其他的线程被称为等待管程.一个

Java知多少(58)线程Runnable接口和Thread类详解

大多数情况,通过实例化一个Thread对象来创建一个线程.Java定义了两种方式: 实现Runnable 接口: 可以继承Thread类. 下面的两小节依次介绍了每一种方式. 实现Runnable接口 创建线程的最简单的方法就是创建一个实现Runnable 接口的类.Runnable抽象了一个执行代码单元.你可以通过实现Runnable接口的方法创建每一个对象的线程.为实现Runnable 接口,一个类仅需实现一个run()的简单方法,该方法声明如下:    public void run( )

Java知多少(56)线程模型

Java运行系统在很多方面依赖于线程,所有的类库设计都考虑到多线程.实际上,Java使用线程来使整个环境异步.这有利于通过防止CPU循环的浪费来减少无效部分. 为更好的理解多线程环境的优势可以将它与它的对照物相比较.单线程系统的处理途径是使用一种叫作轮询的事件循环方法.在该模型中,单线程控制在一无限循环中运行,轮询一个事件序列来决定下一步做什么.一旦轮询装置返回信号表明,已准备好读取网络文件,事件循环调度控制管理到适当的事件处理程序.直到事件处理程序返回,系统中没有其他事件发生.这就浪费了CPU

Java知多少(61)线程优先级

线程优先级被线程调度用来判定何时每个线程允许运行.理论上,优先级高的线程比优先级低的线程获得更多的CPU时间.实际上,线程获得的CPU时间通常由包括优先级在内的多个因素决定(例如,一个实行多任务处理的操作系统如何更有效的利用CPU时间). 一个优先级高的线程自然比优先级低的线程优先.举例来说,当低优先级线程正在运行,而一个高优先级的线程被恢复(例如从沉睡中或等待I/O中),它将抢占低优先级线程所使用的CPU. 理论上,等优先级线程有同等的权利使用CPU.但你必须小心了.记住,Java是被设计成能

JAVA多线程之线程的挂起与恢复(suspend方法与resume方法)

一,介绍 本文讨论JAVA多线程中,使用 thread.suspend()方法暂停线程,使用 thread.resume()恢复暂停的线程 的特点. 先介绍二个关于线程的基本知识: ①线程的执行体是run()方法里面的代码. ②Thread.sleep()方法 使当前正在执行的线程睡眠. 二,suspend()方法 ①当某个线程的suspend()方法被调用时,该线程会被挂起.如果该线程占有了锁,则它不会释放锁.即,线程在挂起的状态下还持有锁. ②suspend()已经是一个过时的方法了. 来分

转: 【Java并发编程】之三:线程挂起、恢复与终止的正确方法(含代码)

转载请注明出处:http://blog.csdn.net/ns_code/article/details/17095733 挂起和恢复线程     Thread 的API中包含两个被淘汰的方法,它们用于临时挂起和重启某个线程,这些方法已经被淘汰,因为它们是不安全的,不稳定的.如果在不合适的时候挂起线程(比如,锁定共享资源时),此时便可能会发生死锁条件--其他线程在等待该线程释放锁,但该线程却被挂起了,便会发生死锁.另外,在长时间计算期间挂起线程也可能导致问题. 下面的代码演示了通过休眠来延缓运行