Java中死锁的原理实战分析

本文实例讲述了Java中死锁的原理。分享给大家供大家参考,具体如下:

一 点睛

当两个线程相互等待对方释放同步监视器时就会发生死锁,Java虚拟机没有监测、也没有采用措施来处理死锁情况,所以多线程编程时应该采取措施避免死锁的出现。

一旦出现死锁,整个程序既不会发生任何异常,也不会给出任何提示,只是所有线程处于阻塞状态,无法继续。

二 代码

class A
{
   public synchronized void foo( B b )
   {
      System.out.println("当前线程名: " + Thread.currentThread().getName()
        + " 进入了A实例的foo()方法" );   // ①
      try
      {
        Thread.sleep(200);
      }
      catch (InterruptedException ex)
      {
        ex.printStackTrace();
      }
      System.out.println("当前线程名: " + Thread.currentThread().getName()
        + " 企图调用B实例的last()方法");  // ③
      b.last();
   }
   public synchronized void last()
   {
      System.out.println("进入了A类的last()方法内部");
   }
}
class B
{
   public synchronized void bar( A a )
   {
      System.out.println("当前线程名: " + Thread.currentThread().getName()
        + " 进入了B实例的bar()方法" );  // ②
      try
      {
        Thread.sleep(200);
      }
      catch (InterruptedException ex)
      {
        ex.printStackTrace();
      }
      System.out.println("当前线程名: " + Thread.currentThread().getName()
        + " 企图调用A实例的last()方法"); // ④
      a.last();
   }
   public synchronized void last()
   {
      System.out.println("进入了B类的last()方法内部");
   }
}
public class DeadLock implements Runnable
{
   A a = new A();
   B b = new B();
   public void init()
   {
      Thread.currentThread().setName("主线程");
      // 调用a对象的foo方法
      a.foo(b);
      System.out.println("进入了主线程之后");
   }
   public void run()
   {
      Thread.currentThread().setName("副线程");
      // 调用b对象的bar方法
      b.bar(a);
      System.out.println("进入了副线程之后");
   }
   public static void main(String[] args)
   {
      DeadLock dl = new DeadLock();
      // 以dl为target启动新线程
      new Thread(dl).start();
      // 调用init()方法
      dl.init();
   }
}

三 运行结果

当前线程名: 主线程 进入了A实例的foo()方法
当前线程名: 副线程 进入了B实例的bar()方法
当前线程名: 主线程 企图调用B实例的last()方法
当前线程名: 副线程 企图调用A实例的last()方法

四 说明

从运行结果来看,程序无法向下执行,也不会抛出任何异常,就一直“僵持”者。

上面代码中的A对象和B对象的方法都是同步方法,也就是A对象和B对象都是同步锁。

程序中有两个线程执行,一个线程的线程执行体是DeadLock类的run()方法,另外一个是DeadLock的init()方法(主线程调用init()方法)。其中run()方法让B对象调用bar()方法,而init()方法让A对象调用foo()方法。

程序运行的流程如下:

  • 1 init()方法先执行,调用A对象的foo()方法,进入foo()方法之前,该线程对A对象加锁,进入foo()方法后,打印一下,然后暂停执行200ms
  • 2 CPU切换到另外一个线程,让B对象执行bar方法,进入bar()方法之前,该线程对B对象加锁,进入bar()方法后,打印一下,然后暂停执行200ms
  • 3 主线程先醒过来,继续向下执行,当调用B对象的last方法时,会被阻塞,因为此时必须对B对象进行加锁,但此时副线程正保持B对象的锁,所以此时主线程会一直等待。
  • 4 副线程会醒过来,会继续往下执行,当调用A对象的last方法时,会被阻塞,因为此时必须对A对象加锁,但此时主线程正保持A对象的锁,所以此时副线程会一直等待。
  • 5 两个线程互相等待对方先释放,所以出现了死锁。

更多java相关内容感兴趣的读者可查看本站专题:《Java进程与线程操作技巧总结》、《Java数据结构与算法教程》、《Java操作DOM节点技巧总结》、《Java文件与目录操作技巧汇总》和《Java缓存操作技巧汇总》

希望本文所述对大家java程序设计有所帮助。

(0)

相关推荐

  • Java死锁_动力节点Java学院整理

    死锁是两个甚至多个线程被永久阻塞时的一种运行局面,这种局面的生成伴随着至少两个线程和两个或者多个资源.在这里我已写好一个简单的程序,它将会引起死锁方案然后我们就会明白如何分析它. Java死锁范例 ThreadDeadlock.java package com.bjpowernode.threads; public class ThreadDeadlock { public static void main(String[] args) throws InterruptedException {

  • java多线程学习之死锁的模拟和避免(实例讲解)

    1.死锁 死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放.由于线程被无限期地阻塞,因此程序不可能正常终止. Java 死锁产生的四个必要条件: 1.互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用 2.不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放. 3.请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有. 4.循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的

  • Java编程之多线程死锁与线程间通信简单实现代码

    死锁定义 死锁是指两个或者多个线程被永久阻塞的一种局面,产生的前提是要有两个或两个以上的线程,并且来操作两个或者多个以上的共同资源:我的理解是用两个线程来举例,现有线程A和B同时操作两个共同资源a和b,A操作a的时候上锁LockA,继续执行的时候,A还需要LockB进行下面的操作,这个时候b资源在被B线程操作,刚好被上了锁LockB,假如此时线程B刚好释放了LockB则没有问题,但没有释放LockB锁的时候,线程A和B形成了对LockB锁资源的争夺,从而造成阻塞,形成死锁:具体其死锁代码如下:

  • java实现死锁的示例代码

    什么是死锁 我们先看看这样一个生活中的例子:在一条河上有一座桥,桥面较窄,只能容纳一辆汽车通过,无法让两辆汽车并行.如果有两辆汽车A和B分别由桥的两端驶上该桥,则对于A车来说,它走过桥面左面的一段路(即占有了桥的一部分资源),要想过桥还须等待B车让出右边的桥面,此时A车不能前进:对于B车来说,它走过桥面右边的一段路(即占有了桥的一部分资源),要想过桥还须等待A车让出左边的桥面,此时B车也不能前进.两边的车都不倒车,结果造成互相等待对方让出桥面,但是谁也不让路,就会无休止地等下去.这种现象就是死锁

  • 详解Java的线程的优先级以及死锁

    Java线程优先级 需要避免的与多任务处理有关的特殊错误类型是死锁(deadlock).死锁发生在当两个线程对一对同步对象有循环依赖关系时.例如,假定一个线程进入了对象X的管程而另一个线程进入了对象Y的管程.如果X的线程试图调用Y的同步方法,它将像预料的一样被锁定.而Y的线程同样希望调用X的一些同步方法,线程永远等待,因为为到达X,必须释放自己的Y的锁定以使第一个线程可以完成.死锁是很难调试的错误,因为: 通常,它极少发生,只有到两线程的时间段刚好符合时才能发生. 它可能包含多于两个的线程和同步

  • 详解Java中synchronized关键字的死锁和内存占用问题

    先看一段synchronized 的详解: synchronized 是 java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行.另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块. 二.然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以

  • Java多线程之死锁的出现和解决方法

    什么是死锁? 死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放.由于线程被无限期地阻塞,因此程序不能正常运行.形象的说就是:一个宝藏需要两把钥匙来打开,同时间正好来了两个人,他们一人一把钥匙,但是双方都再等着对方能交出钥匙来打开宝藏,谁都没释放自己的那把钥匙.就这样这俩人一直僵持下去,直到开发人员发现这个局面. 导致死锁的根源在于不适当地运用"synchronized"关键词来管理线程对特定对象的访问."synchronized"关

  • java避免死锁的常见方法代码解析

    死锁 索是一个非常有用的工具,运用场景非常多,因为它使用起来非常简单,而且易于理解.但同时它也会带来一些困扰,那就是可能会引起死锁,一旦产生死锁,就会造成系统功能不可用.让我们先来看一段代码,这段代码会引起死锁,使线程 thread_1 和线程 thread_2 互相等待对方释放锁. package thread; public class DeadLockDemo { private static String A = "A"; private static String B = &

  • java 多线程死锁详解及简单实例

    java 多线程死锁 相信有过多线程编程经验的朋友,都吃过死锁的苦.除非你不使用多线程,否则死锁的可能性会一直存在.为什么会出现死锁呢?我想原因主要有下面几个方面: (1)个人使用锁的经验差异     (2)模块使用锁的差异     (3)版本之间的差异     (4)分支之间的差异     (5)修改代码和重构代码带来的差异 不管什么原因,死锁的危机都是存在的.那么,通常出现的死锁都有哪些呢?我们可以一个一个看过来,     (1)忘记释放锁 void data_process() { Ent

  • Java 解决死锁的方法实例详解

    死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放.由于线程被无限期地阻塞,因此程序不可能正常终止. java 死锁产生的四个必要条件: 1>互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用 2>不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放. 3>请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的战友. 4>循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P

  • Java 线程死锁的问题解决办法

     Java 线程死锁的问题解决办法 [线程死锁]  原因:两个线程相互等待被对方锁定的资源 代码模拟: public class DeadLock { public static void main(String[] args) { Object obj = new Object(); Object obj1 = new Object(); DeadLockThread1 D1 = new DeadLockThread1(obj, obj1); DeadLockThread2 D2 = new

随机推荐