河北石家庄天气,域名对网站seo的影响吗,pc网站建设的三大条件,桐城建设规划局网站本节书摘来异步社区《Java线程与并发编程实践》一书中的第2章#xff0c;第2.3节#xff0c;作者#xff1a; 【美】Jeff Friesen#xff0c;更多章节内容可以访问云栖社区“异步社区”公众号查看。 2.3 谨防活跃性问题 活跃性这个词代表着某件正确的事情最终会发生。活跃… 本节书摘来异步社区《Java线程与并发编程实践》一书中的第2章第2.3节作者 【美】Jeff Friesen更多章节内容可以访问云栖社区“异步社区”公众号查看。 2.3 谨防活跃性问题 活跃性这个词代表着某件正确的事情最终会发生。活跃性失败发生在应用程序触及一种无法继续执行的状态。在单线程的应用程序中无限循环就是一个例子。多线程应用程序面临着诸如死锁、活锁和饿死的额外挑战。 死锁线程1等待线程2互斥持有的资源而线程2也在等待线程1互斥持有的资源。两条线程都无法继续执行。活锁线程x持续重试一个总是失败的操作以致于无法继续执行。饿死线程x一直被调度器延迟访问其赖以执行的资源。或许是调度器先于低优先级的线程执行高优先级的线程而总是有一个高优先级的线程可以执行。饿死通常也称为无限延迟。死锁会发生在synchronized关键字带来的过多同步上。如果不小心你可能就会遭遇锁同时被多条线程竞争的情形即线程自身缺失继续执行的锁却持有其他线程需要的锁同时由于其他线程持有临界区的锁导致没有一条线程能够通过临界区进而释放自己所持有的锁。清单2-1就是描述该场景的一个典型例子。 清单2-1 一个死锁的问题 public class DeadlockDemo
{private final Object lock1 new Object();private final Object lock2 new Object();public void instanceMethod1(){synchronized(lock1){synchronized(lock2){System.out.println(first thread in instanceMethod1);// critical section guarded first by// lock1 and then by lock2} }}public void instanceMethod2(){synchronized(lock2){synchronized(lock1){System.out.println(second thread in instanceMethod2);// critical section guarded first by// lock2 and then by lock1}}}public static void main(String[] args){final DeadlockDemo dld new DeadlockDemo();Runnable r1 new Runnable(){Overridepublic void run(){while(true){dld.instanceMethod1();try{Thread.sleep(50);}catch (InterruptedException ie){}} }};Thread thdA new Thread(r1);Runnable r2 new Runnable(){Overridepublic void run(){while(true){dld.instanceMethod2();try{Thread.sleep(50);}catch (InterruptedException ie){}}}};Thread thdB new Thread(r2);thdA.start();thdB.start();}
}
清单2-1中线程A和线程B在不同的时间分别调用了instanceMethod1()和instanceMethod2()方法。参考下面的执行序列1线程A调用instanceMethod1()获取到lock1引用对象的锁然后进入它外部的临界区但是还没有获取lock2引用对象的锁。2线程B调用instanceMethod2()获取到lock2引用对象的锁然后进入它外部的临界区但是还没有获取lock1引用对象的锁。3线程A尝试去获取和lock2相关联的锁。JVM强制线程在内部临界区之外等待由于线程B持有那个锁。4线程B尝试去获取和lock1相关联的锁。JVM强制线程在内部临界区之外等待由于线程A持有那个锁。5由于其他线程持有了必要的锁没有一条线程能继续执行。遭遇死锁程序至少在这两条线程的上下文中就冻结住了。照下面那样编译清单2-1 javac DeadlockDemo.java运行程序 java DeadlockDemo你应该能在标准输出流中观测到交替打印的first thread in instance Method1和second thread in instanceMethod2信息直到程序因死锁而冻结。 尽管前面的例子很清晰地识别了死锁的状态但侦测死锁还是不容易。举个例子你的代码可能在多个类中在多个源文件里包含如下的环形关系 类A的同步方法调用了类B的同步方法。类B的同步方法调用了类C的同步方法。类C的同步方法调用了类A的同步方法。如果线程A调用了类A的同步方法线程B调用了类C的同步方法因为线程A还在那个方法当中当线程B尝试调用类A的同步方法时会被阻塞住。线程A会继续执行直至其调用类C的同步方法然后阻塞住。死锁发生了。 注意 Java语言和JVM都没有提供一种方式来避免死锁所以这一任务就落到你的身上。避免死锁最简单的方式就是阻止同步方法或者同步块调用其他的同步方法和同步块。尽管这个建议能避免死锁发生但还是不现实因为在你的某一个同步方法和同步块中很可能需要调用Java API中的同步方法而且这个建议有点因噎废食因为被调用的同步方法和同步块很可能不会调用其他的同步方法和同步块从而不会导致死锁发生。