java - 在Java中无需等待和保持即可锁定许多资源

标签 java multithreading deadlock

我遇到了必须锁定 2 个或更多资源的问题,这导致在使用 ReentrantReadWriteLocks 时出现死锁,即使在各处都有相同的锁定顺序*。 我实现了一种方法,该方法采用锁定对象,锁定所有对象或回滚并抢占当前线程:

/**
 * Helper Interface for an AutoClosable lock.
 */
public interface ResourceLock extends AutoCloseable {

    /**
     * Unlocking doesn't throw any checked exception.
     */
    @Override
    void close();
}
public static ResourceLock lockAll(Lock... locks) {
    List<Lock> successful = new ArrayList<>();
    boolean acquired = false;

    for (final Lock lock : locks) {
        acquired = false;
        try {
            acquired = lock.tryLock(500, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (acquired) {
            successful.add(lock);
        } else {
        break;
        }
    }

    if (!acquired) {
        for (Lock lock1 : successful) {
            lock1.unlock();
        }
        // Preempt the thread and try again
        Thread.yield();
        return lockAll(locks);
    }

    return  () -> {
      for (final Lock lock : locks) {
        lock.unlock();
      }
    };
  }

使用示例:

try (ResourceLock ignored = lockAll(currentNode.getLock().writeLock(), newNode.getLock().readLock())) {
          currentNode.updateCounts(newNode);
}

不太好读。

这是我的问题:
- 如何在 Java 中正确抢占线程?
- 使用 Thread.yield() 可以吗,还是 Thread.sleep(1) 更合适?
——还有比这更优雅的事吗?例如我是否监督了做这件事或某事的最佳实践?在 util.concurrency 中?

*代码应递归地实现概念聚类/Cobweb(Fisher,1987)的多线程版本。锁定顺序始终是父节点、当前访问节点、新节点。但由于线程可能同时位于树的不同级别,因此在某些时候,较高树级别中的子级和较低树级别中的父级之间存在重叠,从而导致死锁。

最佳答案

Is the use of Thread.yield() okay? or would Thread.sleep(1) be more appropriate?

您应该知道 Thread.yield() 根本不能保证执行任何操作。当有人想象 Java 程序可能在 cooperative multitasking 中运行时,这是不合时宜的。环境。协作式多任务处理仍然存在,但您通常不会在功能强大到足以托管 JVM 的系统上找到它。

sleep(1) 调用保证会产生结果,但它会影响程序的性能——如今,一毫秒已经很长了。影响是否太大,这个问题只有你自己才能回答。

我在 Java 代码中见过 sleep(0),但我不知道这是否需要与 yield() 表现出任何不同。

<小时/>

Is there something more elegant than this?

也许不是更优雅,但您可以通过保留树节点的全局Set来避免锁定和解锁多个操作系统互斥体(即Lock对象)的开销被“锁定”,并使用单个全局 Lock 对象来控制对 Set 的访问。

关于java - 在Java中无需等待和保持即可锁定许多资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58908006/

相关文章:

java 类路径意外地找到了一个库

process - 从锁定互斥锁的进程退出会导致死锁吗?

java - 验证用户输入,检查输入是否为正数而不是字符串

java - 反序列化响应的一部分为空

java - 局部变量可以在方法外使用吗?

.net - AppDomain.UnhandledException 未捕获未处理的异常

java - 在多线程中使用图形

java - 线程在 Java 聊天应用程序中的行为不符合我的要求

algorithm - 无死锁与无饥饿

java - 静态 block 中thread.join()引起的死锁