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

所属分类: 软件编程 / java 阅读数: 63
收藏 0 赞 0 分享

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

为充分理解死锁,观察它的行为是很有用的。下面的例子生成了两个类,A和B,分别有foo( )和bar( )方法。这两种方法在调用其他类的方法前有一个短暂的停顿。主类,名为Deadlock,创建了A和B的实例,然后启动第二个线程去设置死锁环境。foo( )和bar( )方法使用sleep( )强迫死锁现象发生。

// An example of deadlock.
class A {
  synchronized void foo(B b) {
    String name = Thread.currentThread().getName();
    System.out.println(name + " entered A.foo");
    try {
      Thread.sleep(1000);
    } catch(Exception e) {
      System.out.println("A Interrupted");
    }
    System.out.println(name + " trying to call B.last()");
    b.last();
  }
  synchronized void last() {
    System.out.println("Inside A.last");
  }
}
class B {
  synchronized void bar(A a) {
    String name = Thread.currentThread().getName();
    System.out.println(name + " entered B.bar");
    try {
      Thread.sleep(1000);
    } catch(Exception e) {
      System.out.println("B Interrupted");
    }
    System.out.println(name + " trying to call A.last()");
    a.last();
  }
  synchronized void last() {
    System.out.println("Inside A.last");
  }
}
class Deadlock implements Runnable {
  A a = new A();
  B b = new B();
  Deadlock() {
    Thread.currentThread().setName("MainThread");
    Thread t = new Thread(this, "RacingThread");
    t.start();
    a.foo(b); // get lock on a in this thread.
    System.out.println("Back in main thread");
  }
  public void run() {
    b.bar(a); // get lock on b in other thread.
    System.out.println("Back in other thread");
  }
  public static void main(String args[]) {
    new Deadlock();
  }
}

运行程序后,输出如下:

MainThread entered A.foo
RacingThread entered B.bar
MainThread trying to call B.last()
RacingThread trying to call A.last()

因为程序死锁,你需要按CTRL-C来结束程序。在PC机上按CTRL-BREAK(或在Solaris下按CTRL-\)你可以看到全线程和管程缓冲堆。你会看到RacingThread在等待管程a时占用管程b,同时,MainThread占用a等待b。该程序永远都不会结束。像该例阐明的,你的多线程程序经常被锁定,死锁是你首先应检查的问题。

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

为充分理解死锁,观察它的行为是很有用的。下面的例子生成了两个类,A和B,分别有foo( )和bar( )方法。这两种方法在调用其他类的方法前有一个短暂的停顿。主类,名为Deadlock,创建了A和B的实例,然后启动第二个线程去设置死锁环境。foo( )和bar( )方法使用sleep( )强迫死锁现象发生。

// An example of deadlock.
class A {
  synchronized void foo(B b) {
    String name = Thread.currentThread().getName();
    System.out.println(name + " entered A.foo");
    try {
      Thread.sleep(1000);
    } catch(Exception e) {
      System.out.println("A Interrupted");
    }
    System.out.println(name + " trying to call B.last()");
    b.last();
  }
  synchronized void last() {
    System.out.println("Inside A.last");
  }
}
class B {
  synchronized void bar(A a) {
    String name = Thread.currentThread().getName();
    System.out.println(name + " entered B.bar");
    try {
      Thread.sleep(1000);
    } catch(Exception e) {
      System.out.println("B Interrupted");
    }
    System.out.println(name + " trying to call A.last()");
    a.last();
  }
  synchronized void last() {
    System.out.println("Inside A.last");
  }
}
class Deadlock implements Runnable {
  A a = new A();
  B b = new B();
  Deadlock() {
    Thread.currentThread().setName("MainThread");
    Thread t = new Thread(this, "RacingThread");
    t.start();
    a.foo(b); // get lock on a in this thread.
    System.out.println("Back in main thread");
  }
  public void run() {
    b.bar(a); // get lock on b in other thread.
    System.out.println("Back in other thread");
  }
  public static void main(String args[]) {
    new Deadlock();
  }
}

运行程序后,输出如下:

MainThread entered A.foo
RacingThread entered B.bar
MainThread trying to call B.last()
RacingThread trying to call A.last()

因为程序死锁,你需要按CTRL-C来结束程序。在PC机上按CTRL-BREAK(或在Solaris下按CTRL-\)你可以看到全线程和管程缓冲堆。你会看到RacingThread在等待管程a时占用管程b,同时,MainThread占用a等待b。该程序永远都不会结束。像该例阐明的,你的多线程程序经常被锁定,死锁是你首先应检查的问题。

更多精彩内容其他人还在看

JavaWeb项目部署到服务器详细步骤详解

这篇文章主要介绍了JavaWeb项目如何部署到服务器,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

IDEA基于支付宝小程序搭建springboot项目的详细步骤

这篇文章主要介绍了IDEA基于支付宝小程序搭建springboot项目的详细步骤,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

详解SpringBoot应用服务启动与安全终止

这篇文章主要介绍了SpringBoot应用服务启动与安全终止,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

Spring Boot启动及退出加载项的方法

这篇文章主要介绍了Spring Boot启动及退出加载项的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

Spring Data Jpa 自动生成表结构的方法示例

这篇文章主要介绍了Spring Data Jpa 自动生成表结构的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

IDEA中osgi的开发应用指南详解

这篇文章主要介绍了IDEA中osgi的开发应用指南详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

详解用maven将dubbo工程打成jar包运行

这篇文章主要介绍了详解用maven将dubbo工程打成jar包运行,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

详解Java合并数组的两种实现方式

这篇文章主要介绍了Java合并数组的两种实现方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

使用Jenkins Pipeline自动化构建发布Java项目的方法

这篇文章主要介绍了使用Jenkins Pipeline自动化构建发布Java项目的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

使用Maven配置Spring的方法步骤

这篇文章主要介绍了使用Maven配置Spring的方法步骤,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享
查看更多