【问题标题】:ReentrantLock lock and unlock by always the same threadReentrantLock 总是由同一个线程锁定和解锁
【发布时间】:2019-03-14 13:05:09
【问题描述】:

我正在尝试在多线程上实现可重入锁,但由于某种原因,同一个线程解锁然后再次锁定,导致始终运行同一个线程,因此执行相同的操作。

下面是线程是如何产生的代码

IntStream.range(0,(NUMBER_OF_THREADS)).forEach(index ->{
            boolean operation = (index % 2 == 0) ? true : false;
            Thread t = new Thread(new Client(operation,this));
            t.start();
});

这是线程的运行函数的工作原理

@Override
public void run() {
    while(!Thread.interrupted()) {
        System.out.println("Trying to acquire lock : " + main.getLock().tryLock()
                + " thread id " + Thread.currentThread().getName());
       // if (main.getLock().tryLock()) {
        try {
            main.getLock().lock();
            if(main.getLock().isHeldByCurrentThread()) {
                System.out.println("Lock held by this thread " + main.getLock().isHeldByCurrentThread()
                        + " thread id : " + Thread.currentThread().getName());
                if (operation) {
                    main.getcAaccount().deposit(1);
                } else {
                    main.getcAaccount().withdraw(2);
                }
                Thread.currentThread().sleep(3000);
            }
        } catch (InterruptedException e) {
                e.printStackTrace();
        } finally {
            System.out.println("Thread id : " + Thread.currentThread().getName() + " unlocking");
            main.getLock().unlock();//always have the unlock part here to ensure it unlock
        }
}

它正确打印出其他 5 个线程正在尝试获取锁并失败,然后线程 id...正在解锁...并立即再次锁定相同的线程,即使它应该处于睡眠状态。

我在这个逻辑场景中遗漏了什么吗?

提前谢谢你。

编辑建议修复的屏幕截图。

【问题讨论】:

  • 你的目标是什么?你想完成什么?
  • 你已经通过tryLock()获得了锁,为什么还要调用lock()
  • 阻塞的并发,一个线程存入另一个线程,但顺序无关紧要。我只是不明白为什么同一个线程在应该休眠时解锁然后获取锁

标签: java multithreading reentrantlock


【解决方案1】:

重入要求每个锁都跟随着后续的解锁。例如,如果我调用lock.lock() 3 次,预计我也会调用lock.unlock() 3 次。在这一系列事件发生之前,ReentrantLock 不会认为自己已解锁。

您没有意识到lock.tryLock(),如果成功,将基本上像调用lock.lock()。所以通过locking 两次,您还需要unlock 两次。在您的代码示例中,您只解锁一次,因此最初锁定的线程在技术上仍然拥有锁。

修复它应该很简单,您可以从代码中删除第二个lock.lock(),互斥应该仍然成立。要么,或者如果你需要阻塞锁定,然后将 lock.tryLock() 替换为 lock.lock()

根据您的编辑,您解决了一个删除额外锁定的问题,但现在您遇到了时间问题。你真的不需要tryLock。您可以用lock 替换它,因为lock 调用将暂停线程并在锁已被持有时阻塞(最终在调用解锁时唤醒)。

【讨论】:

  • 我已经按照你说的做了,但还是同样的问题。我将编辑发布带有您建议的修复的屏幕截图。
  • 好的,那么您遇到了时间问题。考虑我用lock 替换tryLock 的第二点。无需sleep,因为无论如何都会在lock() 上阻塞线程。
  • 我删除了 if(lock.tryLock()) ,现在只有同一个线程自己工作。奇怪的东西。我的意思是其他 5 个线程不打印任何获取锁的尝试。我会为你发布更新的代码
  • 你用lock.lock()替换了tryLock?
  • 天哪,就像我经常说的那样,简单而愚蠢的东西会破坏复杂的东西。再次感谢你。就像一个魅力一样,不同的线程现在获得锁,并且在存款和取款之间以任意方式(无论哪个线程获得锁)进行循环。再次感谢您的宝贵时间。我已投票并接受为答案。
猜你喜欢
  • 1970-01-01
  • 2012-01-07
  • 2016-07-24
  • 2016-08-07
  • 2011-07-24
  • 1970-01-01
  • 2023-03-21
  • 2023-03-24
相关资源
最近更新 更多