当前位置: 动力学知识库 > 问答 > 编程问答 >

java - 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. 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.

网友答案:

With java.util.concurrent.locks.ReentrantLock, you can specify a fairness policy that's relevant here. Passing true to the referenced constructor requests that the lock "play fair." 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:

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). 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. See the implementation in AbstractQueuedSynchronizer$unparkSuccessor() for the specific walk forward from the CLH queue's head toward its tail. A will be closer to the head than B.

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. 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(); unlike the timed ReentrantLock#tryLock(long, TimeUnit), the former does not honor the fairness policy.

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. 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.

网友答案:

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.

分享给朋友:
您可能感兴趣的文章:
随机阅读: