Lock应用之 线程公平竞争

Lock的实现类ReentrantLock的构造函数提供了两种锁获取公平性选择,公平与非公平,默认为非公平,这相比传统的内部锁只使用非公平机制提供了更灵活的选择。

何谓公平与非公平?简单的说就是非公平竞争机制允许插队,而公平竞争机制不允许插队。公平竞争机制下,所有线程都必须排队按顺序来获得锁,,即先到先服务。非公平竞争机制下,新线程在请求锁时如果锁刚好释放,可以及时抢占锁,而不让给排在队头的线程,但如果锁已经被占用新线程也只能排队,排在队列中的线程还是先到先服务,所以保证每个线程都会最后得到锁以做到相对公平。

公平竞争机制下,刚开始锁可用:

非公平竞争机制下,刚开始锁可用:

那么实际应用中究竟选择公平锁还是非公平锁?据统计(本人的测试结果与统计相左),一般场景下非公平锁的性能好于公平锁,而且除非算法依赖于线程公平排队顺序,正常场景下非公平锁都能使程序正常运行,所以无特殊情况推荐使用非公平锁。哪些情况使用非公平锁:

最后,谈谈自己对内部锁、公平锁、非公平锁的性能测试结果。测试环境为Win7 64bbit + JDK7 + 4GB + i5 4*2.67G,从测试结果看,线程少时(小于1000),性能相差无几,公平锁和内部锁反而微胜非公平锁,这也验证了内部锁的性能已经大大提升的说法;但当线程越多时竞争越激烈就能体现出非公平锁的优势。因为公平锁主要用于特殊场景,所以比较它们的性能意义不大,本测试代码只供参考。

import java.util.concurrent.CountDownLatch;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class TestLockFairness {private static final int JOB_NUM = 100;private static final int JOB_LOAD_FACTOR = 500;private Lock lock;private volatile boolean isUsingLock;private CountDownLatch countDownLatch;private void doShortJobWithLock(){lock.lock();try{for(int i=0; i<100; i++){;;}}finally{lock.unlock();}for(int i=0; i<10000; i++){;;}}private void doLongJobWithLock(){lock.lock();try{try {TimeUnit.MICROSECONDS.sleep(JOB_LOAD_FACTOR);} catch (InterruptedException e) {e.printStackTrace();}}finally{lock.unlock();}for(int i=0; i<10000; i++){;;}}private void doShortJob(){synchronized(this){for(int i=0; i<100; i++){;;}}for(int i=0; i<10000; i++){;;}}private void doLongJob(){synchronized(this){try {TimeUnit.MICROSECONDS.sleep(JOB_LOAD_FACTOR);} catch (InterruptedException e) {e.printStackTrace();}}for(int i=0; i<10000; i++){;;}}private class ShortJobWorker implements Runnable{@Overridepublic void run() {for(int i=0; i<JOB_NUM; i++){if(isUsingLock){doShortJobWithLock();}else{doShortJob();}}countDownLatch.countDown();}}private class LongJobWorker implements Runnable{@Overridepublic void run() {for(int i=0; i<JOB_NUM; i++){if(isUsingLock){doLongJobWithLock();}else{doLongJob();}}countDownLatch.countDown();}}public static void main(String[] args) throws InterruptedException {TestLockFairness testLockFairness = new TestLockFairness();System.out.println(“Type\tThreads\tTime”);testLockFairness.test(“synchronized”, false, 10, null);testLockFairness.test(“unfair Lock”, true, 10, new ReentrantLock(false));testLockFairness.test(“fair Lock “, true, 10, new ReentrantLock(true));testLockFairness.test(“synchronized”, false, 100, null);testLockFairness.test(“unfair Lock”, true, 100, new ReentrantLock(false));testLockFairness.test(“fair Lock “, true, 100, new ReentrantLock(true));testLockFairness.test(“synchronized”, false, 500, null);testLockFairness.test(“unfair Lock”, true, 500, new ReentrantLock(false));testLockFairness.test(“fair Lock “, true, 500, new ReentrantLock(true));}private void test(String type, boolean isUsingLock, int threadNum, Lock lock) throws InterruptedException {this.isUsingLock = isUsingLock;this.lock = lock;countDownLatch = new CountDownLatch(2*threadNum);long beginTime = System.currentTimeMillis();for(int i=0; i<threadNum; i++){new Thread(new LongJobWorker()).start();new Thread(new ShortJobWorker()).start();}countDownLatch.await();long endTime = System.currentTimeMillis();System.out.println(type + “\t” + 2*threadNum + ” \t” + (endTime – beginTime));}}

参考:《Java Currency in Practice》

本文出自 “力量来源于赤诚的爱!” 博客,请务必保留此出处

午餐,晚餐。或许吃得不好,可是却依旧为对方擦去嘴角的油渍。

Lock应用之 线程公平竞争

相关文章:

你感兴趣的文章:

标签云: