公平锁和非公平锁

本文详细解析了公平锁与非公平锁的概念、实现原理及优缺点,并通过Java ReentrantLock实例展示了两者的不同运行结果,帮助读者理解锁机制在多线程环境中的应用。

概述

在一个线程组里,能保证每个线程都能拿到锁,那么这个锁就是公平锁。相反,如果保证不了每个线程都能拿到锁,也就是存在有线程饿死,那么这个锁就是非公平锁。

实现原理

那如何能保证每个线程都能拿到锁呢,队列FIFO是一个完美的解决方案,也就是先进先出,java的ReenTrantLock也就是用队列实现的公平锁和非公平锁。

在公平的锁中,如果有另一个线程持有锁或者有其他线程在等待队列中等待这个锁,那么新发出的请求的线程将被放入到队列中。而非公平锁上,只有当锁被某个线程持有时,新发出请求的线程才会被放入队列中(此时和公平锁是一样的)。所以,它们的差别在于非公平锁会有更多的机会去抢占锁。

案例Demo

公平锁

public class FairLockDemo {

    private ReentrantLock lock;

    public FairLockDemo(boolean isFair){
        lock = new ReentrantLock(isFair);
    }

    public void method1(){
        try{
            lock.lock();
            System.out.println("ThreadName=" + Thread.currentThread().getName()
                    + "获取锁定");
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        final FairLockDemo fairLockDemo = new FairLockDemo(true);

        Runnable runnable = new Runnable() {

            @Override
            public void run() {
                System.out.println("★线程" + Thread.currentThread().getName()
                        + "运行了");
                fairLockDemo.method1();
            }
        };

        Thread[] threadArray = new Thread[10];
        for (int i = 0; i < 10; i++) {
            threadArray[i] = new Thread(runnable);
        }

        for (int i = 0; i < 10; i++) {
            threadArray[i].start();
        }

    }

}

运行结果

★线程Thread-3运行了
ThreadName=Thread-3获取锁定
★线程Thread-7运行了
ThreadName=Thread-7获取锁定
★线程Thread-0运行了
ThreadName=Thread-0获取锁定
★线程Thread-2运行了
ThreadName=Thread-2获取锁定
★线程Thread-8运行了
ThreadName=Thread-8获取锁定
★线程Thread-1运行了
ThreadName=Thread-1获取锁定
★线程Thread-5运行了
ThreadName=Thread-5获取锁定
★线程Thread-9运行了
ThreadName=Thread-9获取锁定
★线程Thread-6运行了
ThreadName=Thread-6获取锁定
★线程Thread-4运行了
ThreadName=Thread-4获取锁定

非公平锁

public class FairLockDemo {

    private ReentrantLock lock;

    public FairLockDemo(boolean isFair){
        lock = new ReentrantLock(isFair);
    }

    public void method1(){
        try{
            lock.lock();
            System.out.println("ThreadName=" + Thread.currentThread().getName()
                    + "获取锁定");
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        final FairLockDemo fairLockDemo = new FairLockDemo(false);

        Runnable runnable = new Runnable() {

            @Override
            public void run() {
                System.out.println("★线程" + Thread.currentThread().getName()
                        + "运行了");
                fairLockDemo.method1();
            }
        };

        Thread[] threadArray = new Thread[10];
        for (int i = 0; i < 10; i++) {
            threadArray[i] = new Thread(runnable);
        }

        for (int i = 0; i < 10; i++) {
            threadArray[i].start();
        }

    }

}

运行结果

★线程Thread-0运行了
ThreadName=Thread-0获取锁定
★线程Thread-4运行了
ThreadName=Thread-4获取锁定
★线程Thread-8运行了
ThreadName=Thread-8获取锁定
★线程Thread-2运行了
ThreadName=Thread-2获取锁定
★线程Thread-1运行了
ThreadName=Thread-1获取锁定
★线程Thread-5运行了
ThreadName=Thread-5获取锁定
★线程Thread-6运行了
★线程Thread-9运行了
ThreadName=Thread-9获取锁定
ThreadName=Thread-6获取锁定
★线程Thread-3运行了
ThreadName=Thread-3获取锁定
★线程Thread-7运行了
ThreadName=Thread-7获取锁定

ReentrantLock是一共非公平锁,当构造方法传入ture时,可以变成公平锁;

优缺点

非公平锁性能高于公平锁性能。首先,在恢复一个被挂起的线程与该线程真正运行之间存在着严重的延迟。而且,非公平锁能更充分的利用cpu的时间片,尽量的减少cpu空闲的状态时间。

使用场景

使用场景的话呢,其实还是和他们的属性一 一相关,举个栗子:如果业务中线程占用(处理)时间要远长于线程等待,那用非公平锁其实效率并不明显,但是用公平锁会给业务增强很多的可控制性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值