在Java中无需等待就锁定许多资源

问题描述 投票:0回答:1

我遇到了必须锁定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)。锁定顺序始终是父节点,当前访问的节点,新节点。但是由于线程可能同时处于树的不同级别中,因此在某些时候,较高的子级和较低的树级中的父级之间会出现重叠,从而导致死锁。

java multithreading deadlock
1个回答
0
投票

使用Thread.yield()可以吗?还是Thread.sleep(1)更合适?

您应该注意,Thread.yield()根本不能保证做任何事情。从有人想象Java程序可能在cooperative multitasking环境中运行的时代开始,这是过时的。协作多任务仍然存在,但是在功能强大到可以承载JVM的系统上,您通常不会找到它。

sleep(1)调用is肯定会屈服,但这会影响程序的性能-这些天来很长的时间是毫秒。影响是否太大是一个只有您可以回答的问题。

我已经在Java代码中看到了sleep(0),但是我不知道这是否需要与yield()有所不同。

© www.soinside.com 2019 - 2024. All rights reserved.