【问题标题】:Using Timeout to avoid deadlock in Java multithreading使用 Timeout 避免 Java 多线程中的死锁
【发布时间】:2012-11-24 08:32:31
【问题描述】:

在 Java 多线程中避免死锁情况的策略之一是使用超时。 假设,一个线程已经获得了一个资源的锁,现在正在等待另一个资源的锁。在一定时间后,如果它无法获得资源 2 上的锁,则它应该停止等待资源 2 上的锁。它还应该释放对资源 1 的锁定。这样可以避免死锁。

但是如何在 Java 中实现呢?如何显式“释放”锁?如何定义超时等待锁定。

什么是确切的 java 命令和语法。请问有什么好样的例子吗?

【问题讨论】:

  • 其他解决方案;总是以相同的顺序获取锁,或者从不获取多个锁。 ;)
  • +1 How to define timeout to wait for lock

标签: java multithreading locking timeout deadlock


【解决方案1】:

Java 8+ Concurrency API 中,您可以为lock 设置一个明确的等待时间:

private Lock lock = new ReentrantLock();
private Condition myCondition = lock.newCondition();

try{            
    myCondition.await(1200L, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
    System.out.println((e);
} finally{
    lock.unlock();
}

锁会一直等到它收到来自另一个线程的signal()signalAll() 或直到1.2 秒的时间到期。

【讨论】:

    【解决方案2】:

    这是一个人为的示例,其中包含 2 个锁和 2 个线程,它们试图以不同的顺序获取它们。没有超时,代码就会死锁。

    public static void main(String[] args) throws Exception {
        final ReentrantLock lock1 = new ReentrantLock();
        final ReentrantLock lock2 = new ReentrantLock();
        Runnable try1_2 = getRunnable(lock1, "lock 1", lock2, "lock 2");
        Runnable try2_1 = getRunnable(lock2, "lock 2", lock1, "lock 1");
        new Thread(try1_2).start();
        new Thread(try2_1).start();
    }
    
    private static Runnable getRunnable(final ReentrantLock lock1, final String lock1Name, final ReentrantLock lock2, final String lock2Name) {
        return new Runnable() {
            @Override
            public void run() {
                try {
                    if (lock1.tryLock(1, TimeUnit.SECONDS)) {
                        System.out.println(lock1Name + " acquired in thread " + Thread.currentThread());
                        if (lock2.tryLock(1, TimeUnit.SECONDS)) {
                            System.out.println(lock2Name + " acquired in thread " + Thread.currentThread());
                            Thread.sleep(2000);
                        } else {
                            System.out.println("Could not acquire "+lock2Name + " in thread " + Thread.currentThread());
                            lock1.unlock();
                            System.out.println(lock1Name + " released in thread " + Thread.currentThread());
                        }
                    } else {
                        System.out.println("Could not acquire " + lock1Name + " in thread " + Thread.currentThread());
                    }
                } catch (InterruptedException e) {
                    //you should not ignore it
                } finally {
                    if (lock1.isHeldByCurrentThread()) lock1.unlock();
                    if (lock2.isHeldByCurrentThread()) lock2.unlock();
                }
            }
        };
    }
    

    【讨论】:

    • Java 并发实践示例!! ;)
    • @assylias 当调用对象的同步方法时,线程会自动尝试“锁定该对象”。而在使用“java.util.concurrent.locks.Lock”时,我们不会请求我们正在调用其方法的“锁定对象该对象”。所以我认为,要正确使用“锁定”类,我们不应该将方法标记为同步。但是我们应该有一个与该对象关联的“Lock”实例。在调用需要同步的代码之前,我们应该在相关锁上使用 tryLock()。 ----请继续阅读下面的评论------
    • @NarendraPathai 可能 - 老实说,我没有从那里得到它。
    • @assylias 我不是说你抄的。 :) 只记得它是在里面给的!干杯!很好的例子!
    • @KaushikLele 最后有一个锁(无论是显式锁还是同步方法)(除其他外)以防止两个线程同时执行相同的代码块。因此,您可以使用其中之一,但无需同时使用两者(如果这样做,您会重新引入死锁风险)。
    【解决方案3】:

    Lock in Java

    Use tryLock(timeout, timeunits);
    

    如果在给定的等待时间空闲并且 当前线程没有被中断。如果锁可用这个 方法立即返回值true

    如果没有锁 可用,则当前线程变为 disabled 线程 调度目的并处于休眠状态,直到三件事之一 发生:

    锁被当前线程获取

    或其他一些线程 中断当前线程,获取锁的中断是 支持的;

    或指定的等待时间过去

    【讨论】:

      【解决方案4】:

      希望对您有帮助,

      Lock lock = null;
      lock=....;
      if (lock.tryLock(15L, TimeUnit.SECONDS)) {
          try {
             ........
          } finally {
              lock.unlock();
          }
      } else {
            // do sumthing
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-03-20
        • 1970-01-01
        相关资源
        最近更新 更多