JUC之公平锁与非公平锁

ReentrantLock抢票案例

java 复制代码
class Ticket
{
    private int number = 30;
    ReentrantLock lock = new ReentrantLock();
    //ReentrantLock lock = new ReentrantLock(true);

    public void sale()
    {
        lock.lock();
        try
        {
            if(number > 0)
            {
                System.out.println(Thread.currentThread().getName()+"卖出第:\t"+(number--)+"\t 还剩下:"+number);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}



public class SaleTicketDemo
{
    public static void main(String[] args)
    {
        Ticket ticket = new Ticket();

        new Thread(() -> { for (int i = 0; i <35; i++)  ticket.sale(); },"a").start();
        new Thread(() -> { for (int i = 0; i <35; i++)  ticket.sale(); },"b").start();
        new Thread(() -> { for (int i = 0; i <35; i++)  ticket.sale(); },"c").start();
    }
}

非公平锁演示:

b没有抢到票,基本都被c抢了。

非公平锁

  • 默认是非公平锁
  • 非公平锁可以插队,买卖票不均匀。
  • 是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请 的线程比先申请的线程优先获取锁,在高并发环境下,有可能造成优先级翻转或饥饿的状态(某个线程一直得不到锁)

改成公平锁后的效果

java 复制代码
package com.sgm.springboottest.demos.web;

import java.util.concurrent.locks.ReentrantLock;

class Ticket
{
    private int number = 30;
//    ReentrantLock lock = new ReentrantLock();
    ReentrantLock lock = new ReentrantLock(true);

    public void sale()
    {
        lock.lock();
        try
        {
            if(number > 0)
            {
                System.out.println(Thread.currentThread().getName()+"卖出第:\t"+(number--)+"\t 还剩下:"+number);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}



public class SaleTicketDemo
{
    public static void main(String[] args)
    {
        Ticket ticket = new Ticket();

        new Thread(() -> { for (int i = 0; i <35; i++)  ticket.sale(); },"a").start();
        new Thread(() -> { for (int i = 0; i <35; i++)  ticket.sale(); },"b").start();
        new Thread(() -> { for (int i = 0; i <35; i++)  ticket.sale(); },"c").start();
    }
}

abc均匀的抢到了票

公平锁

  • ReentrantLock lock = new ReentrantLock(true);
  • 买卖票一开始a占优,后面a b c a b c a b c均匀分布
  • 是指多个线程按照申请锁的顺序来获取锁,这里类似排队买票,先来的人先买后来的人在队尾排着,这是公平的

为什么会有公平锁/非公平锁的设计?为什么默认是非公平?

  • 恢复挂起的线程到真正锁的获取还是有时间差的,从开发人员来看这个时间微乎其微,但是从CPU的角度来看,这个时间差存在的还是很明显的。所以非公平锁能更充分的利用CPU 的时间片,尽量减少 CPU 空闲状态时间。

  • 使用多线程很重要的考量点是线程切换的开销,当采用非公平锁时,当1个线程请求锁获取同步状态,然后释放同步状态,因为不需要考虑是否还有前驱节点,所以刚释放锁的线程在此刻再次获取同步状态的概率就变得非常大,所以就减少了线程的开销。

什么时候用公平?什么时候用非公平?

如果为了更高的吞吐量 ,很显然非公平锁是比较合适的 ,因为节****省很多线程切换时间,吞吐量自然就上去了; 否则那就用公平锁,大家公平使用。

相关推荐
斯普润布特6 小时前
物联网-Spring+Netty 框架整合
java·物联网·netty
简简单单就是我_hehe6 小时前
后端链路追踪局部采集和全量采集配置说明
java·开发语言
zshs0006 小时前
#从偶发无字幕到补偿探测链路:一次 B 站字幕导入问题的完整收敛过程
java·后端·重构
存在的五月雨6 小时前
SpringBoot 基于数据库的动态定时任务管理器实现方案
java·spring boot
椰羊~王小美7 小时前
@RequestMapping注解的各个属性作用
java
Yeh2020587 小时前
request与response笔记
java·前端·笔记
程序员老邢7 小时前
【产品底稿 07】商助慧 Admin 运维模块落地:从 “能跑” 到 “能运维”,3 个页面搞定日常排障
java·运维·经验分享·spring boot·后端
元宝骑士7 小时前
Spring @Async 异步无法获取当前登录用户?Sa-Token 1.34.0 终极踩坑解决方案
java·后端
0xDevNull8 小时前
Java项目中Redis热点Key自动检测方案详细教程
java·spring boot·redis
一嘴一个橘子8 小时前
MP 自定义业务方法 (三)
java