【问题标题】:Explicit locks acquisition order, between signaled threads and threads initially acquiring the lock, in Java显式锁获取顺序,在发出信号的线程和最初获取锁的线程之间,在 Java 中
【发布时间】:2014-01-16 17:32:48
【问题描述】:

方法Condition.newCondition()的Javadoc声明“等待方法返回的线程重新获取锁的顺序与最初获取锁的线程相同,默认情况下未指定,但为了公平起见锁有利于那些等待时间最长的线程。"

这是否意味着,对于显式锁,从条件中唤醒的线程与最初获取锁的线程一起竞争锁获取,就像隐式锁一样?

换句话说,有两组线程,一组是第一次尝试获取锁,另一组是在等待条件并发出信号后尝试重新获取锁,是后者在锁获取上比前者更受青睐?

锁公平值是否会以任何方式影响这两组的锁获取顺序?

【问题讨论】:

  • 除非你有一个公平的锁,否则它应该是“未定义的”(即它实际上取决于你的操作系统线程调度程序)。操作系统可能不知道线程是否已经在等待并且现在是否正在重新获取,因此这些组之间应该没有区别。另一方面,公平锁更喜欢最长的等待,无论它们等待的原因是什么。

标签: java multithreading locking


【解决方案1】:

换句话说,有两组线程,一组是第一次尝试获取锁,另一组是在等待条件并发出信号后尝试重新获取锁,是后者在锁获取上比前者更受青睐?

不,除非Lock 是“公平的”,否则很可能是相反的:典型的实现倾向于只获取Lock 的线程,因为让该线程成功而不是让该线程进入睡眠和唤醒另一个。

锁公平值是否会以任何方式影响这两组的锁获取顺序?

不,此时锁定获取没有任何区别。当一个线程等待Condition 发出信号时,可能有其他线程等待更长的时间等待第一次获取。而一个“公平的”Lock 会更喜欢等待时间最长的线程。

【讨论】:

    【解决方案2】:

    对于公平锁,在单选后请求锁的函数必须在锁队列的末尾排队。

    以下短程序演示了这种行为。

    • T1 先获取锁,然后根据与该锁关联的条件调用 await。
    • T2 然后获取锁并等待,直到 T3 也尝试获取锁,然后根据条件调用信号。
    • T3 在获得 T2 持有的锁之前会等待一段时间。

    当 T2 调用信号时,T1 会尝试重新获取锁。当 T2 释放锁时,T1 和 T3 都在竞争锁,但 T3 先获得锁。

    public class Test {
    
        public static void main(String[] args) throws Exception {
            final Lock r = new ReentrantLock(true);
            final Condition c = r.newCondition();
    
            Thread t1 = new Thread( () -> { 
                System.out.println("T1 try lock");
                r.lock(); 
                System.out.println("T1 got lock");
                System.out.println("T1 invokes await and releases lock");
                try { c.await(); } catch (InterruptedException e) { }
                System.out.println("T1 reqcquired lock");
                r.unlock();
            } );
            Thread t2 = new Thread( () -> {
                sleep(50);
                System.out.println("T2 try lock");
                r.lock();
                System.out.println("T2 got lock");
                sleep(100);
                c.signal();
                System.out.println("T2 signaled");
                sleep(100);
                r.unlock();
            } );
            Thread t3 = new Thread( () -> {
                sleep(100);
                System.out.println("T3 try lock");
                r.lock();
                System.out.println("T3 got lock");
                r.unlock();
            } );
            t1.start();
            t2.start();
            t3.start();
        }
    
        static void sleep(long millis) {
            try { Thread.sleep(millis); } catch (InterruptedException e) {  }
        }
    
    }
    

    输出是

    T1 try lock
    T1 got lock
    T1 invokes await and releases lock
    T2 try lock
    T2 got lock
    T3 try lock
    T2 signaled
    T3 got lock
    T1 got signal and reqcquired lock
    

    【讨论】:

      猜你喜欢
      • 2015-08-13
      • 2013-10-28
      • 2021-08-13
      • 2017-07-13
      • 1970-01-01
      • 1970-01-01
      • 2022-08-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多