下面通过一段代码来说明线程死锁。
public class DeadLockTest { private static Object resource1 = new Object(); private static Object resource2 = new Object(); public static void main(String[] args){ //创建线程1 Thread thread1 = new Thread(new Runnable(){ @Override public void run() { synchronized (resource2) { System.out.println("线程1持有资源2"); try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println("线程1等待获取资源1"); synchronized (resource1) { System.out.println("线程1持有资源1"); } } } }); //创建线程2 Thread thread2 = new Thread(new Runnable(){ @Override public void run() { synchronized (resource1) { System.out.println("线程2持有资源1"); try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println("线程2等待获取资源2"); synchronized (resource2) { System.out.println("线程2持有资源2"); } } } }); thread1.start(); thread2.start(); } }
运行结果如下图所示:
代码首先创建了两个资源, 并创建了两个线程。 从输出结果可以知道, 线程调度器先CPU 资源分配给了线程1,线程1使用 synchronized(resource2) 方法获取到了 resource2的监视器锁,然后调用 sleep 函数休眠1秒,休眠 1秒是为了保证线程1在获取 resource1对应的锁前让线程2抢占到CPU, 获取到资源 resource1上的锁。 线程1调用 sleep方法后线程2会执行synchronized (resource1) 方法,这代表线程2获取到了 resource1对象的监视器锁, 然后调用sleep函数休眠1秒。
到了这里线程1获取到 了resource2 资源, 线程2获取到了 resource1资源。线程1休眠结束后会企图获取 resource1资源, 而 resource1资源被线程2所持有, 所以线程1会被阻塞而等待。 而同时线程2休眠结束后 会企图获取 resource2资源, 而 resource2资源己经被线程1持有,所以线程1和线程2就陷入了相互等待的状态, 也就产生了死锁。
如何避免线程死锁
造成死锁的原因其实和申请资源的顺序有很大关系, 使用资源分配的有序性原则就可以避免死锁。
资源分配有序性就是指,假如线程1和线程2都需要资源 1, 2, 3, … , n 时,对资源进行排序,线程1和线程2只有在获取了资源 n-1 时才能去获取资源 n。
将线程1的代码修改如下:
Thread thread1 = new Thread(new Runnable(){ @Override public void run() { synchronized (resource1) { System.out.println("线程1持有资源1"); try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println("线程1等待获取资源2"); synchronized (resource2) { System.out.println("线程1持有资源2"); } } } });
运行结果如下图
如上代码让在线程 1中获取资源的顺序和在线程2中获取资源的顺序保持一致,即可避免死锁的发生。
限 时 特 惠: 本站每日持续更新海量各大内部创业教程,一年会员只需98元,全站资源免费下载 点击查看详情
站 长 微 信: lzxmw777