在ReentrantLock中,对于公平和非公平的定义是通过对同步器AbstractQueuedSynchronizer的扩展加以实现的
非公平的获取语义:
公平的获取语义:
比较非公平的获取,仅加入了当前线程(Node)之前是否有前置节点在等待的判断
编写一个测试来观察公平和非公平锁在获取锁时的区别,在测试用例中定义了内部
类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; } } }
调用非公平方法,返回结果:
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.
调用公平方法,返回结果:
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.
可以明显看出,在非公平获取的过程中,“插队”现象非常严重,后续获取锁的线程根本不顾及sync队列中等待的线程,而是能获取就获取。反观公平获取的过程,锁的获取就类似线性化的