|
1.12 暂停线程 |
暂停线程意味着此线程还可以恢复运行,在Java多线程中,可以使用suspend()方法暂停线程,使用resume()方法来恢复线程的执行。
本节将讲述suspend()方法与resume()方法的使用。
创建测试用的项目suspend_resume_test,文件MyThread.java代码如下:
package mythread; public class MyThread extends Thread { private long i = 0; public long getI() { return i; } public void setI(long i) { this.i = i; } @Override public void run() { while (true) { i++; } } }
文件Run.java代码如下:
package test.run; import mythread.MyThread; public class Run { public static void main(String[] args) { try { MyThread thread = new MyThread(); thread.start(); Thread.sleep(5000); // A段 thread.suspend(); System.out.println("A= " + System.currentTimeMillis() + " i=" + thread.getI()); Thread.sleep(5000); System.out.println("A= " + System.currentTimeMillis() + " i=" + thread.getI()); // B段 thread.resume(); Thread.sleep(5000); // C段 thread.suspend(); System.out.println("B= " + System.currentTimeMillis() + " i=" + thread.getI()); Thread.sleep(5000); System.out.println("B= " + System.currentTimeMillis() + " i=" + thread.getI()); } catch (InterruptedException e) { e.printStackTrace(); } } }
程序运行结果如图1-54所示。
图1-54 暂停与恢复的测试
stop()方法用于销毁线程对象,如果想继续运行线程,则必须使用start()方法重新启动线程,而suspend()方法用于让线程不再执行任务,线程对象并不销毁,在当前所执行的代码处暂停,未来还可以恢复运行。
从控制台输出的时间上来看,线程的确被暂停了,而且可以恢复成运行状态。
如果suspend()方法与resume()方法使用不当,极易造成公共同步对象被独占,其他线程无法访问公共同步对象的结果。
创建suspend_resume_deal_lock项目,文件SynchronizedObject.java代码如下:
package testpackage; public class SynchronizedObject { synchronized public void printString() { System.out.println("begin"); if (Thread.currentThread().getName().equals("a")) { System.out.println("a线程永远 suspend了!"); Thread.currentThread().suspend(); } System.out.println("end"); } }
文件Run.java代码如下:
package test.run; import testpackage.SynchronizedObject; public class Run { public static void main(String[] args) { try { final SynchronizedObject object = new SynchronizedObject(); Thread thread1 = new Thread() { @Override public void run() { object.printString(); } }; thread1.setName("a"); thread1.start(); Thread.sleep(1000); Thread thread2 = new Thread() { @Override public void run() { System.out.println("thread2启动了,但进入不了printString()方法!只打印1个begin"); System.out.println("因为printString()方法被a线程锁定并且永远suspend暂停了!"); object.printString(); } }; thread2.start(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
程序运行结果如图1-55所示。
另外一种独占锁的情况也需要格外注意,稍有不注意,就会掉进“坑”里。创建测试用的项目suspend_resume_LockStop,类MyThread.java代码如下:
package mythread; public class MyThread extends Thread { private long i = 0; @Override public void run() { while(true) { i++; } } }
图1-55 独占并锁死
类Run.java代码如下:
package test.run; import mythread.MyThread; public class Run { public static void main(String[] args) { try { MyThread thread = new MyThread(); thread.start(); Thread.sleep(1000); thread.suspend(); System.out.println("main end!"); } catch (InterruptedException e) { e.printStackTrace(); } } }
程序运行结果如图1-56所示。
图1-56 控制台输出main end信息
进程状态在控制台中呈红色按钮显示,说明进程并未销毁。虽然main线程销毁了,但是MyThread呈暂停状态,所以进程不会销毁。
但如果将线程类MyThread.java更改如下:
package mythread; public class MyThread extends Thread { private long i = 0; @Override public void run() { while (true) { i++; System.out.println(i); } } }
再次运行程序,控制台不输出main end,如图1-57所示。
图1-57 不输出main end信息
出现这种情况的原因是当程序运行到System.out.println(i)方法内部停止时,同步锁是不释放的,println()方法源代码如图1-58所示。
图1-58 锁不释放
当前PrintStream对象的println()方法一直呈“暂停”状态,并且“锁未释放”,而main()方法中的代码“System.out.println("main end!");”也需要这把锁,main线程并未销毁,造成迟迟不能输出main end。
虽然suspend()方法是过期作废的方法,但研究其过期作废的原因是很有必要的。
在使用suspend()方法与resume()方法时也容易出现线程暂停,进而导致数据不完整的情况。
创建项目suspend_resume_nosameValue,文件MyObject.java代码如下:
package myobject; public class MyObject { private String username = "1"; private String password = "11"; public void setValue(String u, String p) { this.username = u; if (Thread.currentThread().getName().equals("a")) { System.out.println("停止a线程!"); Thread.currentThread().suspend(); } this.password = p; } public void printUsernamePassword() { System.out.println(username + " " + password); } }
文件Run.java代码如下:
package test; import myobject.MyObject; public class Run { public static void main(String[] args) throws InterruptedException { final MyObject myobject = new MyObject(); Thread thread1 = new Thread() { public void run() { myobject.setValue("a", "aa"); }; }; thread1.setName("a"); thread1.start(); Thread.sleep(500); Thread thread2 = new Thread() { public void run() { myobject.printUsernamePassword(); }; }; thread2.start(); } }
程序运行结果如图1-59所示。
图1-59 程序运行结果
程序运行结果出现值不完整的情况,所以在程序中使用suspend()方法要格外注意。
这两个方法被标识为作废过期的,想要实现对线程进行暂停与恢复的处理,可使用wait()、notify()或notifyAll()方法。