/** * 通过休眠来延缓运行,模拟长时间运行的情况,使线程更可能在不适当的时候被挂起 * 说明:如果在不合适的时候挂起线程(如锁定共享资源时),此时便可能会发生死锁条件--其它线程在等待该线程释放锁, * 但该线程却被挂起,便会发生死锁。 */ public class DeprecatedSuspendResume extends Object implements Runnable{ private volatile int firstVal; private volatile int secondVal; public boolean areValuesEqual() { return (firstVal == secondVal); } @Override public void run() { try { firstVal = 0; secondVal = 0; workMethod(); } catch (InterruptedException e) { System.out.println("[DeprecatedSuspendResume] interrupted while in workMethod()"); } } private void workMethod() throws InterruptedException { int val = 1; while (true) { /** * 若设置firstVal之后,但在设置secondVal之前,挂起新线程会产生麻烦 */ stepOne(val); stepTwo(val); val++; // 再次循环前休眠200 ms Thread.sleep(200); } } /** * 赋值后,休眠300ms,从而使线程有机会在stepOne()和stepTwo()之间被挂起 */ private void stepOne(int newVal) throws InterruptedException { firstVal = newVal; // 模拟长时间运行的情况 Thread.sleep(300); } private void stepTwo(int newVal) { secondVal = newVal; } public static void main(String[] args) { DeprecatedSuspendResume dsr = new DeprecatedSuspendResume(); Thread thread = new Thread(dsr); thread.start(); // 休眠1 s,让其它线程有机会获得执行 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 10; i++) { // 挂起线程 thread.suspend(); System.out.println("[DeprecatedSuspendResume] dsr.areValuesEqual() = " + dsr.areValuesEqual() + " [main]= " + Thread.currentThread().getId() + " [thread]=" + thread.getId()); // 恢复线程 thread.resume(); try { // 线程随机休眠0~2 s Thread.sleep((long)(Math.random()*2000.0)); } catch (InterruptedException e) { } } // 中断应用程序 System.exit(0); } }
/** * 实现线程挂起和恢复的策略--设置标志位,可以在线程的指定位置实现线程的挂起和恢复,而不用担心其不确定性。 */ public class AlternateSuspendResume extends Object implements Runnable { private volatile int firstVal; private volatile int secondVal; /** * 增加标志位,用来实现线程的挂起和恢复 */ private volatile boolean suspended; public boolean areValuesEqual() { return (firstVal == secondVal); } @Override public void run() { try { suspended = false; firstVal = 0; secondVal = 0; workMethod(); } catch (InterruptedException e) { System.out.println("[AlternateSuspendResume] interrupted while in workMethod()"); } } private void workMethod() throws InterruptedException { int val = 1; while (true) { // 仅当线程挂起时,才运行这行代码 waitWhileSuspended(); stepOne(val); stepTwo(val); val++; // 仅当线程挂起时,才运行这行代码 waitWhileSuspended(); Thread.sleep(200); } } private void stepOne(int newVal) throws InterruptedException { firstVal = newVal; Thread.sleep(300); } private void stepTwo(int newVal) { secondVal = newVal; } public void suspendRequest() { suspended = true; } public void resumeRequest() { suspended = false; } private void waitWhileSuspended() throws InterruptedException { // 这是一个“繁忙等待”技术的示例 while (suspended) { Thread.sleep(200); } } public static void main(String[] args) { AlternateSuspendResume asr = new AlternateSuspendResume(); Thread thread = new Thread(asr); thread.start(); // 休眠1 s,让其它线程有机会获得执行 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } /** * 设置firstVal之后,但在设置secondVal之前,挂起新线程 * 此处休眠目的是为了防止在执行asr.areValuesEqual()进行比较时, * 恰逢stepOne操作执行完,而stepTwo操作还没执行 */ try { Thread.sleep(350); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 10; i++) { asr.suspendRequest(); System.out.println("[AlternateSuspendResume] asr.areValuesEqual()= " + asr.areValuesEqual() + "[main]= " + Thread.currentThread().getId() + "[thread]= " + thread.getId()); asr.resumeRequest(); } try { // 线程随机休眠0~2 s Thread.sleep((long)(Math.random() * 2000.0)); } catch (InterruptedException e) { e.printStackTrace(); } // 退出应用程序 System.exit(0); } }