在Java中,死锁是多线程的一种情况,线程1等待线程2获得对象锁,线程2等待线程1获得对象锁。这里,线程1和线程2都互相等待释放锁。 Java 中的多线程程序可能会导致死锁,因为关键字synchronized 会在等待与所提到的对象链接的监视器或锁时阻塞执行线程。让我们在以下部分中看到死锁的工作原理和示例。
开始您的免费软件开发课程
网络开发、编程语言、软件测试及其他
正如所讨论的,同步方法可以锁定代码的特定部分。对于Java中的每个对象,都会有一个锁,同步是一种锁定函数或代码块的技术,以确保一次只有1个线程可以访问该函数或代码块。
当特定线程需要执行同步函数时,它首先尝试获取锁。同时,如果另一个线程已经收到锁,则第一个线程将等待,直到线程 2 释放锁。尽管同步可以防止数据不一致的问题,但仍然存在同步问题。
假设有 2 个线程,“线程 1”和“线程 2”。线程 1 已获得对象 1 的锁定,线程 2 已获得对象 2 的锁定。线程 1 执行方法 1,想要获得对象 2 的锁定。但是,线程 2 已经获得对象 2 的锁定。
此外,线程2还需要获得对象1的锁;但是,线程 1 拥有对象 1 上的锁。此时,线程 1 和线程 2 这两个线程都无法完成其执行,只能永远等待该锁。这种情况称为死锁。
下面给出了提到的示例:
实现死锁的Java程序。
代码:
public class DeadLockExample { //main method public static void main(String[] args) throws InterruptedException { //create three objects 1, 2 and 3 Object o1 = new Object(); Object o2 = new Object(); Object o3 = new Object(); //create three threads 1, 2 and 3 Thread th1 = new Thread(new SynchronizationThread(o1, o2), "thread 1"); Thread th2 = new Thread(new SynchronizationThread(o2, o3), "thread 2"); Thread th3 = new Thread(new SynchronizationThread(o3, o1), "thread 3"); //start thread 1 th1.start(); //thread sleeps for 5000 seconds Thread.sleep(5000); //start thread 2 th2.start(); //thread sleeps for 5000 seconds Thread.sleep(5000); //start thread 3 th3.start(); } } class SynchronizationThread implements Runnable { private Object o1; private Object o2; public SynchronizationThread(Object o1, Object o2){ this.o1=o1; this.o2=o2; } //function run @Override public void run() { //store the name of the thread String nm = Thread.currentThread().getName(); System.out.println( nm + " attaining lock on "+ o1 ) ; synchronized (o1) { System.out.println( nm + " attained lock on "+ o1 ) ; work(); System.out.println( nm + " attaining lock on "+ o2 ) ; synchronized (o2) { System.out.println( nm + " attained lock on "+ o2 ); work(); } System.out.println( nm + " released lock on "+ o2 ) ; } System.out.println( nm + " released lock on "+ o1 ) ; System.out.println( nm + " completed execution.") ; } //function work private void work() { try { //thread sleeps Thread.sleep(30000); } //catch the exception catch (InterruptedException exc) { exc.printStackTrace(); } } }
输出:
在这个程序中,3个正在运行的线程共享一个资源,并且它们以获取对象1上的锁的方式运行,但是当它尝试获取对象2上的锁时,它会进入等待状态。为了防止死锁,可以将代码重写如下。
代码:
public class DeadLockExample { public static void main(String[] args) throws InterruptedException { Object o1 = new Object(); Object o2 = new Object(); Object o3 = new Object(); Thread th1 = new Thread(new SynchronizationThread(o1, o2), "thread 1"); Thread th2 = new Thread(new SynchronizationThread(o2, o3), "thread 2"); Thread th3 = new Thread(new SynchronizationThread(o3, o1), "thread 3"); //start thread 1, 2 and 3 th1.start(); //thread sleeps for 5000 seconds Thread.sleep(5000); th2.start(); //thread sleeps for 5000 seconds Thread.sleep(5000); th3.start(); } } class SynchronizationThread implements Runnable{ private Object o1; private Object o2; public SynchronizationThread(Object o1, Object o2){ this.o1=o1; this.o2=o2; } //function run @Override public void run() { //store the name of the thread String nm = Thread.currentThread().getName(); System.out.println( nm + " attaining lock on "+ o1 ) ; synchronized (o1) { System.out.println( nm + " attained lock on "+ o1 ) ; work(); } System.out.println( nm + " released lock on "+ o1 ) ; System.out.println( nm + " acquiring lock on " + o2 ); synchronized (o2) { System.out.println( nm + " attained lock on "+ o2 ); work(); } System.out.println( nm + " released lock on "+ o2 ) ; System.out.println( nm + " released lock on "+ o1 ) ; System.out.println( nm + " completed execution.") ; } //function work private void work() { try { //thread sleeps Thread.sleep(30000); } //catch the exception catch (InterruptedException exc) { exc.printStackTrace(); } } }
输出:
以下是有助于避免死锁情况的指南。
嵌套锁是导致死锁的常见原因之一。如果另一资源已持有一个资源,请勿锁定该资源以避免死锁。如果用户仅使用 1 个对象,则不可能导致死锁。
人们建议仅锁定必要的资源。但是,即使不需要,某些用户也可能会尝试锁定资源。
如果两个线程借助线程连接无限期地等待对方完成,就会发生死锁。如果线程需要等待其他线程完成,最好使用具有等待线程完成的最大时间的 join。
以上是Java 中的死锁的详细内容。更多信息请关注PHP中文网其他相关文章!