简体   繁体   English

如果两个线程正在等待进入同步方法,那么当互斥锁被释放时,它们是按照它们到达的顺序执行的吗?

[英]If two threads are waiting to enter a synchronized method, when the mutex is released do they execute in the order they arrived?

If I have a synchronized method and two threads are waiting to enter it they seem to enter the thread Last In First Executed. 如果我有一个synchronized方法并且两个线程正在等待输入它们,则它们似乎进入Last In First Executed线程。 Is there a way to make this First In First Executed? 有没有办法让这首先被执行?

This is the unit test that I'm using: 这是我正在使用的单元测试:

package com.test.thread;

import org.apache.log4j.Logger;
import org.junit.Test;

public class ThreadTest {
    private static final Logger log = Logger.getLogger(ThreadTest.class);

    @Test
    public void testThreading() throws InterruptedException {
        Thread t1 = new Thread(new Runnable() {    
            public void run() { synchd("1"); }
        });
        Thread t2 = new Thread(new Runnable() {    
            public void run() { synchd("2"); }
        });
        Thread t3 = new Thread(new Runnable() {    
            public void run() { synchd("3"); }
        });

        t3.start();
        Thread.sleep(5);
        t1.start();
        t2.start();

        Thread.sleep(12000);
    }

    public static synchronized void synchd(String output) {
        log.debug(output);
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            // do nothing
        }

    }
}

The output for this is always 3, 2, 1, and I'd like to find a way for it to be 3, 1, 2. 这个输出总是3,2,1,我想找到一个方法,它是3,1,2。

No, they are not executed in their order of arrival. 不,他们没有按照他们的到达顺序执行。

The execution order depends on lots of parameters relative to threads scheduling and is most often unpredictable. 执行顺序取决于与线程调度相关的大量参数,并且通常是不可预测的。

With java.util.concurrent.locks.ReentrantLock , you can specify a fairness policy that's relevant here. 使用java.util.concurrent.locks.ReentrantLock ,您可以在此处指定相关的公平策略。 Passing true to the referenced constructor requests that the lock "play fair." true传递给引用的构造函数请求锁定“公平”。 What that means is a little vague in the documentation, but studying the documentation for the underlying AbstractQueuedSynchronizer type and the implementation of ReentrantLock$FairSync (in the Sun JDK) gives additional hints: 这意味着在文档中有点模糊,但研究底层AbstractQueuedSynchronizer类型的文档和ReentrantLock$FairSync (在Sun JDK中)的实现提供了额外的提示:

Namely, when one thread attempts to acquire the lock in fair mode, it will not "barge" ahead of other waiting threads; 也就是说,当一个线程试图以公平模式获取锁时,它不会在其他等待线程之前“插入”; if any other threads are waiting for the lock, the newly arriving thread will "get it line." 如果有任何其他线程正在等待锁定,则新到达的线程将“获取它”。

Now, it's still possible —though highly unlikely—that this newly-queued thread will acquire the lock next when it's next released by its current holder, if it by then happens to wind up as first in line due to predecessors being interrupted, but observe that even though the logical model for a condition queue is a set of waiting threads, in the aforementioned implementation it is in fact a queue (a CLH Queue , described in its application to the Java library in the paper The java.util.concurrent Synchronizer Framework ). 现在,仍然有可能 -尽管极不可能 - 这个新排队的线程将在下一次由其当前持有者释放时获得锁定,如果它由于前任被中断而恰好成为第一线,但观察即使条件队列的逻辑模型是一等待线程,在前面提到的实现中它实际上是一个队列 (一个CLH队列 ,在其应用程序中描述的Java库中的java.util.concurrent Synchronizer)框架 )。 In the fair mode, only the first item in the queue will acquire the lock. 公平模式下,只有队列中的第一个项目才能获得锁定。

Obviously, two threads can race when trying to acquire the lock "at the same time." 显然,当试图“同时”获取锁时,两个线程可能会竞争。 With a fair lock, you can expect that if thread A arrives first and calls Lock#lock() , and winds up having to wait because the lock is held by thread C , and later thread B arrives and calls Lock#lock() while thread C still holds it, B will get in line behind the already-queued A , and once C releases the lock, A will get a chance before B to acquire it. 使用公平锁定,你可以预期如果线程A首先到达并调用Lock#lock() ,并且最终必须等待,因为锁由线程C保持 ,后来线程B到达并调用Lock#lock()而线程C仍然保持它, B将在已经排队的A 后面排队,并且一旦C释放锁定, A将在B获得它之前获得机会。 See the implementation in AbstractQueuedSynchronizer$unparkSuccessor() for the specific walk forward from the CLH queue's head toward its tail. 请参阅AbstractQueuedSynchronizer$unparkSuccessor()的实现, AbstractQueuedSynchronizer$unparkSuccessor()从CLH队列的头部向其尾部的特定前进。 A will be closer to the head than B . AB更接近头部。

The documentation for ReentrantLock warns that even when operating in fair mode, it's possible that threads already waiting on the lock will lose out to the thread currently holding the lock releasing it and acquiring it again. ReentrantLock的文档警告说,即使在公平模式下运行,已经等待锁的线程也可能会丢失到当前持有锁的线程释放它并再次获取它。 I think —but am not sure—that this can occur when the current thread wins at getting in line ahead of other threads that have not yet landed in the queue. 认为 - 但是我不确定 - 当当前线程在尚未进入队列的其他线程之前获胜时会发生这种情况。 Also, note the warning concerning ReentrantLock#tryLock() ; 另请注意有关ReentrantLock#tryLock()的警告; unlike the timed ReentrantLock#tryLock(long, TimeUnit) , the former does not honor the fairness policy. 与定时的ReentrantLock#tryLock(long, TimeUnit) ,前者不尊重公平政策。

This survey makes some conclusions based on one implementation. 该调查基于一种实施方式得出一些结论。 In general, it's safer to take Mr. Barousse's view : the acquisition ordering is best thought of as being a random grab from a set of waiters. 总的来说,采取Barousse先生的观点更为安全:收购顺序最好被认为是来自一群服务员的随机抓取。 However, with a fairness policy studied in enough depth, you can see that there is some determinism to be had. 但是,如果对公平政策进行深入研究,你会发现存在一些决定论。 It doesn't come for free, though; 但它不是免费的; note the warnings about decreases in throughput when barging is prohibited. 请注意禁止在驳船时减少吞吐量的警告。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM