锁的公平与非公平

Posted 不想下火车的人

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了锁的公平与非公平相关的知识,希望对你有一定的参考价值。

  锁是给线程用的,线程拿到锁之后才能干活。当多个线程竞争一个锁时,同一个时间只能有一个线程脱颖而出持有锁,其他线程等该线程释放锁后发起下一轮竞争。那么这种竞争就存在公平性问题,如果是公平的竞争,那么这些线程就得有序来依次得到锁,这就需要线程们按先来后到排队,第一个线程使用完后把锁递给第二个线程,以此类推。非公平的锁是无序的,举个例子:线程甲持有锁,后面线程乙跑过来争,发现被甲拿了就去睡觉(休眠或者被挂起)了,等线程甲释放锁通知乙来取;过了会儿,乙被唤醒时,刚好线程丙半路杀过来了,把锁拿去用了,而乙还在迷糊着,等丙释放锁时乙刚好完全醒了拿到了锁。

  从上面可以看到,如果竞争很激烈,锁被持有时间短,那么非公平锁能充分利用时间,公平锁反而因为线程的切换浪费了时间。反之,如果线程持有锁的时间长,那么非公平锁会被频繁请求,线程重试次数多,做了很多无用功,公平锁按部就班传递锁。内置锁只能是非公平的,显式锁可以自己定义,下面看个例子:

package com.wulinfeng.concurrent;

import java.util.concurrent.locks.ReentrantLock;

public class FairAndUnfairLock {

    public void doSomething(boolean isFair) {
        ReentrantLock lock = null;
        if (isFair) {
            lock = new ReentrantLock(true); // 公平锁
            printThreadInfo(lock);
        } else {
            lock = new ReentrantLock(); // 非公平锁
            printThreadInfo(lock);
        }

    }

    private void printThreadInfo(ReentrantLock lock) {
        try {
            lock.lock();
            System.out.println(Thread.currentThread().getName() + "获取锁定.");
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        final FairAndUnfairLock fairOrUnfair = new FairAndUnfairLock();
        Thread[] threadArray = new Thread[20];

        System.out.println("非公平锁开始:");

        // 非公平锁
        for (int i = 0; i < 20; i++) {
            threadArray[i] = new Thread(new Runnable() {

                @Override
                public void run() {
                    fairOrUnfair.doSomething(false);
                }
            }, "wulinfeng-" + i);
        }
        for (int i = 0; i < 20; i++) {
            threadArray[i].start();
        }

        // 等非公平锁跑完
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("公平锁开始:");

        // 公平锁
        for (int i = 0; i < 20; i++) {
            threadArray[i] = new Thread(new Runnable() {

                @Override
                public void run() {
                    fairOrUnfair.doSomething(true);
                }
            }, "wulinfeng-" + i);
        }
        for (int i = 0; i < 20; i++) {
            threadArray[i].start();
        }
    }
}

  输出结果:

非公平锁开始:
wulinfeng-11获取锁定.
wulinfeng-2获取锁定.
wulinfeng-9获取锁定.
wulinfeng-6获取锁定.
wulinfeng-7获取锁定.
wulinfeng-10获取锁定.
wulinfeng-1获取锁定.
wulinfeng-0获取锁定.
wulinfeng-12获取锁定.
wulinfeng-8获取锁定.
wulinfeng-4获取锁定.
wulinfeng-3获取锁定.
wulinfeng-5获取锁定.
wulinfeng-16获取锁定.
wulinfeng-14获取锁定.
wulinfeng-13获取锁定.
wulinfeng-18获取锁定.
wulinfeng-15获取锁定.
wulinfeng-17获取锁定.
wulinfeng-19获取锁定.
公平锁开始:
wulinfeng-1获取锁定.
wulinfeng-0获取锁定.
wulinfeng-3获取锁定.
wulinfeng-5获取锁定.
wulinfeng-2获取锁定.
wulinfeng-4获取锁定.
wulinfeng-6获取锁定.
wulinfeng-8获取锁定.
wulinfeng-7获取锁定.
wulinfeng-14获取锁定.
wulinfeng-12获取锁定.
wulinfeng-10获取锁定.
wulinfeng-9获取锁定.
wulinfeng-16获取锁定.
wulinfeng-18获取锁定.
wulinfeng-11获取锁定.
wulinfeng-15获取锁定.
wulinfeng-13获取锁定.
wulinfeng-17获取锁定.
wulinfeng-19获取锁定.

  从上面结果看公平锁只能是大致按顺序来。

以上是关于锁的公平与非公平的主要内容,如果未能解决你的问题,请参考以下文章

公平锁与非公平锁源码对比

可重入的独占锁ReentrantLock概述-公平与非公平锁的实现

公平锁与非公平锁

带你快速了解Java锁中的公平锁与非公平锁

公平锁与非公平锁

公平锁与非公平锁