TicketLock

32 篇文章 0 订阅
18 篇文章 0 订阅

票锁比较直白,可以称为号码锁,叫号锁。是一种自旋锁,之前讲过CLH锁(传送门)也是一种自旋锁。

TicketLock定义

ticket lock就像是平时使用美味不用等一样,自己先通过公众号排队取号,然后不断的会刷新(自旋)当前叫到了第几号,如果叫到自己的号,就说明可以获取锁去吃饭啦。

TicketLock锁流程

假设饭店只有一个位子

  1. 初始时位子是空的,叫号0
  2. 第一位顾客取号,取号0
  3. 匹配号成功,成功就餐
  4. 第二位顾客取号,取号1,当前叫号为0,不匹配,自旋
  5. 第一位顾客用餐结束,工作人员叫号1
  6. 第二位顾客取号1与叫号1匹配,进入就餐。

TicketLock.png

TicketLock实现

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author 会灰翔的灰机
 * @date 2019/9/15
 */
public class TicketLock implements MyLock {

    /**
     * 叫号的号码(排队号)
     */
    private final AtomicInteger SERVICE_NO = new AtomicInteger(-1);
    /**
     * 取号的号码(当前可以获取锁的号)
     */
    private final AtomicInteger CURRENT_SERVICE_NO = new AtomicInteger(0);
    private volatile Integer lockedNO = -1;

    @Override
    public void lock(){
        // 1. 取号
        int number = SERVICE_NO.incrementAndGet();
        // 2. 当前叫号与取号不匹配进入自旋
        while(number != CURRENT_SERVICE_NO.get()) {
            System.out.println("spin:SERVICE_NO="+number+",currentServiceNo="+CURRENT_SERVICE_NO.get());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 3. 当前叫号与取号匹配获取锁成功
        System.out.println("got lock...");
        // 4. 记录当前获取到所资源的编号,解锁时需要匹配,不能随便释放其他人的锁
        lockedNO = number;
    }
    @Override
    public void unlock(){
        // 4. 释放锁,递增叫号唤醒下一个等待锁的排号者
        CURRENT_SERVICE_NO.compareAndSet(lockedNO, lockedNO+1);
        System.out.println("release lock:SERVICE_NO="+SERVICE_NO.get()+",currentServiceNo="+CURRENT_SERVICE_NO.get());
    }

    public static void main(String[] args) {
        TicketLock ticketLock = new TicketLock();
        MyTask myTask = new MyTask(10000, ticketLock);
        myTask.start();
        MyTask myTask2 = new MyTask(1000, ticketLock);
        myTask2.start();
    }

}

TicketLock优点

  1. 公平性
  2. 无饥饿性
  3. 原子操作少,共两处原子操作,其实仅需要一次即可,第二次不需要读取,仅需要一个递增操作不需要读取数值(读取并递增的两个动作合并一个原子操作的开销)

TicketLock缺点

  1. 扩展性差。如果等待者很多,在释放锁时,递增(餐厅服务人员叫号:请100号客人用餐)锁号时,会将其他所有等待线程中的(叫号)锁号缓存cacheline置为无效invalid。会通过内存主线重新加载新的值到缓存cacheline。这样会造成“拥堵”。因为叫号更新了,我手里的号码需要跟最新的叫号号码比较是否相等,如果相等说明到我用餐了
  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值