博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java多线程 -- 公平锁和非公平锁
阅读量:5934 次
发布时间:2019-06-19

本文共 4784 字,大约阅读时间需要 15 分钟。

在java的锁机制中,公平和非公平的参考物是什么,个人而言觉得是相对产生的结果而立,简单的来说,如果一个线程组里,能保证每个线程都能拿到锁,那么这个锁就是公平锁。相反,如果保证不了每个线程都能拿到锁,也就是存在有线程饿死,那么这个锁就是非公平锁。本文围绕ReenTrantLock来讲。

实现原理

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

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

公平锁:

final Thread current = Thread.currentThread();            int c = getState();            if (c == 0) {                if (!hasQueuedPredecessors() &&                    compareAndSetState(0, acquires)) {                    setExclusiveOwnerThread(current);                    return true;                }            }    #hasQueuedPredecessors的实现    public final boolean hasQueuedPredecessors() {           Node t = tail; // Read fields in reverse initialization order        Node h = head;        Node s;        return h != t &&            ((s = h.next) == null || s.thread != Thread.currentThread());    }复制代码

非公平锁:

final Thread current = Thread.currentThread();            int c = getState();            if (c == 0) {                if (compareAndSetState(0, acquires)) {                    setExclusiveOwnerThread(current);                    return true;                }            }复制代码

示例

公平锁:
import java.util.concurrent.locks.ReentrantLock;/** * Created by Fant.J. */public class MyFairLock {    /**     *     true 表示 ReentrantLock 的公平锁     */    private  ReentrantLock lock = new ReentrantLock(true);    public   void testFail(){        try {            lock.lock();            System.out.println(Thread.currentThread().getName() +"获得了锁");        }finally {            lock.unlock();        }    }    public static void main(String[] args) {        MyFairLock fairLock = new MyFairLock();        Runnable runnable = () -> {            System.out.println(Thread.currentThread().getName()+"启动");            fairLock.testFail();        };        Thread[] threadArray = new Thread[50];        for (int i=0; i<50; i++) {            threadArray[i] = new Thread(runnable);            threadArray[i].start();        }    }}复制代码
Thread-0启动获得了锁Thread-0获得了锁Thread-1启动获得了锁Thread-1获得了锁Thread-2启动获得了锁Thread-2获得了锁Thread-3启动获得了锁Thread-3获得了锁Thread-4启动获得了锁Thread-4获得了锁Thread-5启动获得了锁Thread-5获得了锁Thread-6启动Thread-7启动获得了锁Thread-6获得了锁获得了锁Thread-7获得了锁Thread-8启动Thread-9启动获得了锁Thread-8获得了锁Thread-10启动获得了锁Thread-9获得了锁获得了锁Thread-10获得了锁Thread-11启动获得了锁Thread-11获得了锁Thread-13启动获得了锁Thread-13获得了锁Thread-14启动获得了锁Thread-14获得了锁Thread-15启动获得了锁Thread-15获得了锁Thread-16启动获得了锁Thread-16获得了锁Thread-17启动获得了锁Thread-17获得了锁Thread-18启动获得了锁Thread-18获得了锁Thread-19启动获得了锁Thread-19获得了锁Thread-20启动获得了锁Thread-20获得了锁Thread-24启动获得了锁Thread-24获得了锁Thread-22启动获得了锁Thread-22获得了锁Thread-27启动获得了锁Thread-27获得了锁Thread-25启动Thread-26启动获得了锁Thread-25获得了锁获得了锁Thread-26获得了锁Thread-29启动获得了锁Thread-29获得了锁Thread-28启动获得了锁Thread-28获得了锁Thread-30启动获得了锁Thread-30获得了锁Thread-32启动获得了锁Thread-32获得了锁Thread-31启动获得了锁Thread-31获得了锁Thread-33启动获得了锁Thread-33获得了锁Thread-34启动获得了锁Thread-34获得了锁Thread-36启动获得了锁Thread-36获得了锁Thread-35启动获得了锁Thread-35获得了锁Thread-38启动获得了锁Thread-38获得了锁Thread-37启动获得了锁Thread-37获得了锁Thread-39启动获得了锁Thread-39获得了锁Thread-42启动Thread-41启动获得了锁Thread-42获得了锁获得了锁Thread-41获得了锁Thread-40启动获得了锁Thread-40获得了锁Thread-45启动获得了锁Thread-45获得了锁Thread-44启动获得了锁Thread-44获得了锁Thread-43启动获得了锁Thread-43获得了锁Thread-23启动Thread-46启动Thread-21启动获得了锁Thread-23获得了锁Thread-49启动Thread-48启动Thread-12启动获得了锁Thread-46获得了锁Thread-47启动获得了锁Thread-21获得了锁获得了锁Thread-49获得了锁获得了锁Thread-48获得了锁获得了锁Thread-12获得了锁获得了锁Thread-47获得了锁复制代码

可以看到,获取锁的线程顺序正是线程启动的顺序。

非公平锁:

/** * Created by Fant.J. */public class MyNonfairLock {    /**     *     false 表示 ReentrantLock 的非公平锁     */    private  ReentrantLock lock = new ReentrantLock(false);    public  void testFail(){        try {            lock.lock();            System.out.println(Thread.currentThread().getName() +"获得了锁");        }finally {            lock.unlock();        }    }    public static void main(String[] args) {        MyNonfairLock nonfairLock = new MyNonfairLock();        Runnable runnable = () -> {            System.out.println(Thread.currentThread().getName()+"启动");            nonfairLock.testFail();        };        Thread[] threadArray = new Thread[10];        for (int i=0; i<10; i++) {            threadArray[i] = new Thread(runnable);            threadArray[i].start();        }    }}复制代码
Thread-1启动Thread-0启动Thread-0获得了锁Thread-1获得了锁Thread-8启动Thread-8获得了锁Thread-3启动Thread-3获得了锁Thread-4启动Thread-4获得了锁Thread-5启动Thread-2启动Thread-9启动Thread-5获得了锁Thread-2获得了锁Thread-9获得了锁Thread-6启动Thread-7启动Thread-6获得了锁Thread-7获得了锁复制代码

可以看出非公平锁对锁的获取是乱序的,即有一个抢占锁的过程。

最后

那非公平锁和公平锁适合什么场合使用呢,他们的优缺点又是什么呢?

优缺点:

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

使用场景

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

转载地址:http://ljjtx.baihongyu.com/

你可能感兴趣的文章
Linux系统启动流程详解
查看>>
测试人员必学的软件快速测试方法(二)
查看>>
程序员全国不同地区,微信(面试 招聘)群。
查看>>
【干货】界面控件DevExtreme视频教程大汇总!
查看>>
闭包 !if(){}.call()
查看>>
python MySQLdb安装和使用
查看>>
Java小细节
查看>>
poj - 1860 Currency Exchange
查看>>
chgrp命令
查看>>
Java集合框架GS Collections具体解释
查看>>
洛谷 P2486 BZOJ 2243 [SDOI2011]染色
查看>>
linux 笔记本的温度提示
查看>>
数值积分中的辛普森方法及其误差估计
查看>>
Web service (一) 原理和项目开发实战
查看>>
跑带宽度多少合适_跑步机选购跑带要多宽,你的身体早就告诉你了
查看>>
广平县北方计算机第一届PS设计大赛
查看>>
深入理解Java的接口和抽象类
查看>>
java与xml
查看>>
Javascript异步数据的同步处理方法
查看>>
快速排序——Java
查看>>