自定义显示锁(学习记录)

本文介绍了一个改进版的Lock接口,提供了与`synchronized`类似的数据同步机制,但增强了可中断和超时功能,允许线程在一定时间内获取锁或在被阻塞时被中断。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由上一篇 synchronized 理解可以知道,synchronized 提供了一种排他式的数据同步机制,某个线程在获取 monior lock 的时候可能会被阻塞,而这种阻塞有两个很明显的缺陷:

  • 无法控制阻塞时长
  • 阻塞不能被中断

所以此篇文章就实现一个具备 synchronized 关键字所有功能的同时又具备可中断和 lock 超时的功能。
话不多说,开始看接口

import java.util.List;
import java.util.concurrent.TimeoutException;

/**
 * @author hasaki_w_c
 * @version 1.0
 * @date 2021/9/26 15:56
 */
public interface Lock {
    /**
     * 此 lock() 方法永远阻塞,除非获取到了锁,但可以被中断
     * @throws InterruptedException 中断时抛此异常
     */
    void lock() throws InterruptedException;

    /**
     * 可中断,并且有超时功能
     * @param mills 超时时长
     * @throws InterruptedException 中断抛此异常
     * @throws TimeoutException 超时抛此异常
     */
    void lock(long mills) throws InterruptedException, TimeoutException;

    /**
     * 释放锁的方法
     */
    void unlock();

    /**
     * 获取当前哪些线程被阻塞
     * @return 阻塞线程列表
     */
    List<Thread> getBlockedThreads();
}

然后是实现类

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeoutException;

/**
 * @author hasaki_w_c
 * @version 1.0
 * @date 2021/9/26 16:25
 */
public class BooleanLock implements Lock{

    private Thread currentThread;
    private boolean locked = false;
    private final List<Thread> blockedList = new ArrayList<>();

    @Override
    public void lock() throws InterruptedException {
        synchronized (this) {
            //如果当前锁已经被某个线程获得,则该线程加入阻塞队列,并且使当前线程 wait 释放对 this monitor 的所有权
            while (locked) {
                blockedList.add(Thread.currentThread());
                this.wait();
            }
            //如果当前锁没有被其他线程获得,则该线程将尝试从阻塞队列中删除自己
            blockedList.remove(Thread.currentThread());
            //locked 开关被指定为 true
            this.locked = true;
            //记录获取锁的线程
            this.currentThread = Thread.currentThread();
        }
    }

    @Override
    public void lock(long mills) throws InterruptedException, TimeoutException {
        synchronized (this) {
            //判断是否合法,不合法直接调用 lock() 方法
            if (mills <= 0) {
                this.lock();
            }else {
                long remainMills = mills;
                long endMills = System.currentTimeMillis() + remainMills;
                while (locked) {
                    //如果 remainMills 小于等于 0,则意味着当前线程被其他线程唤醒或者在指定的 wait 时间到了之后还没有获得锁,
                    // 这种情况下会抛出超时的异常
                    if (remainMills <= 0) {
                        throw new TimeoutException("can't get the lock during " + mills + " ms.");
                    }
                    if (!blockedList.contains(Thread.currentThread())) {
                        blockedList.add(Thread.currentThread());
                    }
                    //等待 remainMills 的毫秒数,该值最开始是由其他线程传入的,但在多次 wait 的过程中会重新计算
                    this.wait(remainMills);
                    //重新计算 remainMills 时间
                    remainMills = endMills - System.currentTimeMillis();
                }
                //获得该锁,并从 block 列表中删除当前线程,将 locked 的状态修改为 true 并且指定获得锁的线程就是当前线程
                blockedList.remove(Thread.currentThread());
                this.locked = true;
                this.currentThread = Thread.currentThread();
            }
        }
    }

    @Override
    public void unlock() {
        synchronized (this) {
            //判断当前线程是否为获取锁的那个线程,只有加了锁的线程才有资格解锁。
            if (currentThread == Thread.currentThread()) {
                //将锁的 locked 状态修改为 false
                this.locked = false;
                Optional.of(Thread.currentThread().getName() + " release the lock.").ifPresent(System.out::println);
                //通知其他在线程休息室的线程,可以尝试重新获取锁了
                this.notifyAll();
            }
        }
    }

    @Override
    public List<Thread> getBlockedThreads() {
        return Collections.unmodifiableList(blockedList);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

且慢!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值