Lock Application Thread Fair Competition

Source: Internet
Author: User

The ReentrantLock constructor of the Lock implementation class provides two types of Lock obtaining fairness options: Fairness and non-fairness. The default value is unfair, this provides more flexible options than traditional internal locks that only use unfair mechanisms.


What is fairness and non-fairness? Simply put, the unfair competition mechanism allows the jump, while the fair competition mechanism does not. Under the fair competition mechanism, all threads must queue in order to obtain the lock, that is, first come first served. Under the unfair competition mechanism, if the lock is released when a new thread requests a lock, it can seize the lock in time, instead of waiting for the thread in the queue, however, if the lock has been occupied by new threads, it can only be queued, And the threads in the queue are first served, so ensure that each thread will finally get the lock to be relatively fair.


Under the fair competition mechanism, the lock is available at the beginning:

  1. A requests the lock. Because the lock is available, A directly occupies the lock.

  2. B requests the lock. Because the lock is occupied, B enters the waiting queue.

  3. The C request lock is released at the same time. Because B is waiting for the queue, C is directly put into the waiting queue, and B is awakened and locked.


Under the unfair competition mechanism, the lock is available at the beginning:

  1. A requests the lock. Because the lock is available, A directly occupies the lock.

  2. B requests the lock, so B enters the waiting queue.

  3. C requests the lock and A releases the lock. At this time, although B waits for the queue and will be awakened, C will directly participate in the competition to obtain the lock. Generally, C will first obtain the lock, B continues to wait, which is unfair to B, but B can only see that the lock is occupied. However, there is a serious delay between recovering a suspended thread and the thread actually starting to run. Therefore, if C does not occupy the lock for a long time, C has released the lock after B is awakened, at this time, B can directly occupy the lock, which leads to a two-pronged situation. How can C thread make full use of the lock resources and greatly improve the system throughput? This is also the reason why unfair locks have better performance than fair locks in highly competitive scenarios.


So in actual application, should we choose a fair lock or an unfair lock? According to statistics, the test results are different from the statistics. In general, the performance of unfair locks is better than that of fair locks, and unless the algorithm depends on the Fair Queuing order of threads, unfair locks can make programs run normally in normal scenarios. Therefore, we recommend that you use unfair locks without special circumstances. When to use an unfair lock:

  1. Algorithms rely on fair queuing algorithms

  2. The thread holds the lock for a long time.

  3. The average interval between thread request locks is relatively long.


Finally, let's talk about our own performance test results on internal locks, fair locks, and unfair locks. The test environment is Win7 64 bbit + JDK7 + 4 GB + i5 4*2.67 GB. According to the test results, when there are few threads, less than 1000), the performance is almost the same, fair locks and internal locks are slightly better than unfair locks, which also proves that the internal locks have greatly improved their performance; however, the more threads, the more intense the competition will reflect the advantage of unfair locks. Because fair locks are mainly used in special scenarios, it is of little significance to compare their performance. This test code is for reference only.


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{            @Override        public void run() {            for(int i=0; i<JOB_NUM; i++){                if(isUsingLock){                    doShortJobWithLock();                }                else{                    doShortJob();                }            }                                                            countDownLatch.countDown();        }        }                                            private class LongJobWorker implements Runnable{        @Override        public 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));    }}


Reference: Java Currency in Practice

This article is from "the power comes from the sincere love !" Blog, please be sure to keep this source http://stevex.blog.51cto.com/4300375/1300760

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.