有时,线程的挂起是很有用的。例如,一个独立的线程可以用来显示当日的时间。如果用户不希望用时钟,线程被挂起。在任何情形下,挂起线程是很简单的,一旦挂起,重新启动线程也是一件简单的事。
挂起,终止和恢复线程机制在Java 2和早期版本中有所不同。尽管你运用Java 2的途径编写代码,你仍需了解这些操作在早期Java环境下是如何完成的。例如,你也许需要更新或维护老的代码。你也需要了解为什么Java 2会有这样的变化。因为这些原因,下面内容描述了执行线程控制的原始方法,接着是Java 2的方法。
先于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() 恢复继续运行。
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机制控制线程的更多例子。尽管这种机制不像老方法那样“干净”,然而,它是确保运行时不发生错误的方法。它是所有新的代码必须采用的方法。