在ReentrantLock中,對於公平和非公平的定義是經過對同步器AbstractQueuedSynchronizer的擴展加以實現的java
比較非公平的獲取,僅加入了當前線程(Node)以前是否有前置節點在等待的判斷ide
編寫一個測試來觀察公平和非公平鎖在獲取鎖時的區別,在測試用例中定義了內部
類ReentrantLock2,該類主要公開了getQueuedThreads()方法,該方法返回正在等待獲取鎖的線
程列表,因爲列表是逆序輸出,爲了方便觀察結果,將其進行反轉測試
import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class FairAndUnfairTest { private static Lock fairLock = new ReentrantLock2(true); private static Lock unfairLock = new ReentrantLock2(false); public static void main(String[] args) throws Exception { // fair(); unfair(); } public static void fair() { System.out.println("fair version"); for (int i = 0; i < 5; i++) { Thread thread = new Thread(new Job(fairLock)) { public String toString() { return getName(); } }; thread.setName("" + i); thread.start(); } // sleep 5000ms } public static void unfair() { System.out.println("unfair version"); for (int i = 0; i < 5; i++) { Thread thread = new Thread(new Job(unfairLock)) { public String toString() { return getName(); } }; thread.setName("" + i); thread.start(); } // sleep 5000ms } private static class Job implements Runnable { private Lock lock; public Job(Lock lock) { this.lock = lock; } @Override public void run() { for (int i = 0; i < 2; i++) { lock.lock(); try { TimeUnit.SECONDS.sleep(2); System.out.println("Lock by:" + Thread.currentThread().getName() + " and " + ((ReentrantLock2) lock).getQueuedThreads() + " waits."); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } } private static class ReentrantLock2 extends ReentrantLock { public ReentrantLock2(boolean fair) { super(fair); } private static final long serialVersionUID = 1773716895097002072L; public Collection<Thread> getQueuedThreads() { List<Thread> threads = new ArrayList<Thread>(super.getQueuedThreads()); Collections.reverse(threads); return threads; } } }
調用非公平方法,返回結果:this
unfair version
Lock by:0 and [1, 2, 3, 4] waits.
Lock by:0 and [1, 2, 3, 4] waits.
Lock by:1 and [2, 3, 4] waits.
Lock by:1 and [2, 3, 4] waits.
Lock by:2 and [3, 4] waits.
Lock by:2 and [3, 4] waits.
Lock by:3 and [4] waits.
Lock by:3 and [4] waits.
Lock by:4 and [] waits.
Lock by:4 and [] waits.spa
調用公平方法,返回結果:線程
fair version
Lock by:0 and [1, 2, 4, 3] waits.
Lock by:1 and [2, 4, 3, 0] waits.
Lock by:2 and [4, 3, 0, 1] waits.
Lock by:4 and [3, 0, 1, 2] waits.
Lock by:3 and [0, 1, 2, 4] waits.
Lock by:0 and [1, 2, 4, 3] waits.
Lock by:1 and [2, 4, 3] waits.
Lock by:2 and [4, 3] waits.
Lock by:4 and [3] waits.
Lock by:3 and [] waits.code
能夠明顯看出,在非公平獲取的過程當中,「插隊」現象很是嚴重,後續獲取鎖的線程根本不顧及sync隊列中等待的線程,而是能獲取就獲取。反觀公平獲取的過程,鎖的獲取就相似線性化的blog