相信大家都用过Redis分布式锁吧 Redis分布式锁是对某个字符串来进行上锁的 用起来嘎嘎爽
于是我就想能不能自己实现一个根据key来同步的锁?下面为该锁的实现过程

若有线程安全问题或者是讲解不到位的地方,欢迎各位大佬指正。

话不多说直接开搞

首先先写一个锁

static final class Lock extends ReentrantLock {/*** 正在使用或者是准备使用该锁的数量*/int using;/*** 锁的有参构造函数** @param fair 是否公平*/Lock(boolean fair) {super(fair);}}

这个类比较简单 继承自java.util.concurrent.locks.ReentrantLock
然后给他一个using属性

KeyLock
package cn.liziguo.util.concurrent;import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;/*** @author Liziguo* @date 2022/8/12 11:15*/
public class KeyLock<K> {final ConcurrentHashMap<K, Lock> map = new ConcurrentHashMap<>();/*** 是否公平锁*/final boolean fair;/*** 无参构造函数 默认使用非公平锁*/public KeyLock() {fair = false;}/*** 有参构造函数指定是否使用公平锁** @param fair 是否公平*/public KeyLock(boolean fair) {this.fair = fair;}/*** 从map里获取锁 如果存在则返回 不存在则创建* 并使其using++** @param key key* @return lock*/Lock getLock(K key) {return map.compute(key, (k, lock) -> {if (lock == null) {lock = new Lock(fair);}lock.using++;return lock;});}/*** 获取锁 会阻塞** @param key key*/public void lock(K key) {getLock(key).lock();}/*** 尝试获取锁 不阻塞** @param key key* @return 获取成功返回true*/public boolean tryLock(K key) {AtomicBoolean b = new AtomicBoolean();map.compute(key, (k, lock) -> {if (lock == null) {lock = new Lock(fair);}// 由于tryLock是非阻塞的 我们可以直接在map里进行调用if (lock.tryLock()) {// 只有申请成功了才使using++lock.using++;// 把结果传递到外部b.set(true);}return lock;});return b.get();}/*** 尝试获取锁 并指定时间** @param key     key* @param timeout 过期时间* @param unit    时间单位* @return 获取成功返回true*/public boolean tryLock(K key, long timeout, TimeUnit unit) {Lock lock = getLock(key);boolean b;try {b = lock.tryLock(timeout, unit);} catch (InterruptedException e) {b = false;}if (!b) {// 如果锁获取失败 则判断该锁是否被其他进程使用map.computeIfPresent(key, (k, oldLock) -> {// 看看别的地方有没有用着这个锁if (--oldLock.using == 0) {// 如果没有 就释放内存return null;} else {// 否则不管return oldLock;}});}return b;}/*** 释放锁 必须由申请锁的线程进行调用** @param key key*/public void unlock(K key) {map.computeIfPresent(key, (k, lock) -> {// 释放锁lock.unlock();// 看看别的地方有没有用着这个锁if (--lock.using == 0) {// 如果没有 就释放内存return null;} else {// 否则不管return lock;}});}static final class Lock extends ReentrantLock {/*** 正在使用或者是准备使用该锁的数量*/int using;/*** 锁的有参构造函数** @param fair 是否公平*/Lock(boolean fair) {super(fair);}}}

主要是借助java.util.concurrent.ConcurrentHashMap处理线程安全问题

用法

现在这个类的基本功能已经实现并且可以使用了
用法也很简单:

    public static void main(String[] args) {KeyLock<String> keyLock = new KeyLock<>();final String key = "lock:user_id:" + 10001;keyLock.lock(key);try {System.out.println("哈哈哈");} finally {keyLock.unlock(key);}}
扩展api

在此基础上提供几个api提高易用性

    public void lockExecute(K key, Runnable runnable) {lock(key);try {runnable.run();} finally {unlock(key);}}public <T> T lockExecute(K key, Supplier<T> supplier) {lock(key);try {return supplier.get();} finally {unlock(key);}}public boolean tryLockExecute(K key, Runnable runnable) {if (tryLock(key)) {try {runnable.run();return true;} finally {unlock(key);}}return false;}public <T> T tryLockExecute(K key, T failResult, Supplier<T> supplier) {if (tryLock(key)) {try {return supplier.get();} finally {unlock(key);}}return failResult;}

用法:

    public static void main(String[] args) {KeyLock<String> keyLock = new KeyLock<>();final String key = "lock:user_id:" + 10001;keyLock.lockExecute(key, () -> System.out.println("哈哈哈"));}
完整代码
package cn.liziguo.util.concurrent;import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.*;/*** @author Liziguo* @date 2022/8/12 11:15*/
public class KeyLock<K> {final ConcurrentHashMap<K, Lock> map = new ConcurrentHashMap<>();/*** 是否公平锁*/final boolean fair;/*** 无参构造函数 默认使用非公平锁*/public KeyLock() {fair = false;}/*** 有参构造函数指定是否使用公平锁** @param fair 是否公平*/public KeyLock(boolean fair) {this.fair = fair;}/*** 从map里获取锁 如果存在则返回 不存在则创建* 并使其using++** @param key key* @return lock*/Lock getLock(K key) {return map.compute(key, (k, lock) -> {if (lock == null) {lock = new Lock(fair);}lock.using++;return lock;});}/*** 获取锁 会阻塞** @param key key*/public void lock(K key) {getLock(key).lock();}/*** 尝试获取锁 不阻塞** @param key key* @return 获取成功返回true*/public boolean tryLock(K key) {AtomicBoolean b = new AtomicBoolean();map.compute(key, (k, lock) -> {if (lock == null) {lock = new Lock(fair);}// 由于tryLock是非阻塞的 我们可以直接在map里进行调用if (lock.tryLock()) {// 只有申请成功了才使using++lock.using++;// 把结果传递到外部b.set(true);}return lock;});return b.get();}/*** 尝试获取锁 并指定时间** @param key     key* @param timeout 过期时间* @param unit    时间单位* @return 获取成功返回true*/public boolean tryLock(K key, long timeout, TimeUnit unit) {Lock lock = getLock(key);boolean b;try {b = lock.tryLock(timeout, unit);} catch (InterruptedException e) {b = false;}if (!b) {// 如果锁获取失败 则判断该锁是否被其他进程使用map.computeIfPresent(key, (k, oldLock) -> {// 看看别的地方有没有用着这个锁if (--oldLock.using == 0) {// 如果没有 就释放内存return null;} else {// 否则不管return oldLock;}});}return b;}/*** 释放锁 必须由申请锁的线程进行调用** @param key key*/public void unlock(K key) {map.computeIfPresent(key, (k, lock) -> {// 释放锁lock.unlock();// 看看别的地方有没有用着这个锁if (--lock.using == 0) {// 如果没有 就释放内存return null;} else {// 否则不管return lock;}});}public void lockExecute(K key, Runnable runnable) {lock(key);try {runnable.run();} finally {unlock(key);}}public boolean lockExecute(K key, BooleanSupplier supplier) {lock(key);try {return supplier.getAsBoolean();} finally {unlock(key);}}public int lockExecute(K key, IntSupplier supplier) {lock(key);try {return supplier.getAsInt();} finally {unlock(key);}}public long lockExecute(K key, LongSupplier supplier) {lock(key);try {return supplier.getAsLong();} finally {unlock(key);}}public double lockExecute(K key, DoubleSupplier supplier) {lock(key);try {return supplier.getAsDouble();} finally {unlock(key);}}public <T> T lockExecute(K key, Supplier<T> supplier) {lock(key);try {return supplier.get();} finally {unlock(key);}}public boolean tryLockExecute(K key, Runnable runnable) {if (tryLock(key)) {try {runnable.run();return true;} finally {unlock(key);}}return false;}public boolean tryLockExecute(K key, boolean failResult, BooleanSupplier supplier) {if (tryLock(key)) {try {return supplier.getAsBoolean();} finally {unlock(key);}}return failResult;}public int tryLockExecute(K key, int failResult, IntSupplier supplier) {if (tryLock(key)) {try {return supplier.getAsInt();} finally {unlock(key);}}return failResult;}public long tryLockExecute(K key, long failResult, LongSupplier supplier) {if (tryLock(key)) {try {return supplier.getAsLong();} finally {unlock(key);}}return failResult;}public double tryLockExecute(K key, double failResult, DoubleSupplier supplier) {if (tryLock(key)) {try {return supplier.getAsDouble();} finally {unlock(key);}}return failResult;}public <T> T tryLockExecute(K key, T failResult, Supplier<T> supplier) {if (tryLock(key)) {try {return supplier.get();} finally {unlock(key);}}return failResult;}public boolean tryLockExecute(K key, BooleanSupplier failSupplier, BooleanSupplier supplier) {if (tryLock(key)) {try {return supplier.getAsBoolean();} finally {unlock(key);}}return failSupplier.getAsBoolean();}public int tryLockExecute(K key, IntSupplier failSupplier, IntSupplier supplier) {if (tryLock(key)) {try {return supplier.getAsInt();} finally {unlock(key);}}return failSupplier.getAsInt();}public long tryLockExecute(K key, LongSupplier failSupplier, LongSupplier supplier) {if (tryLock(key)) {try {return supplier.getAsLong();} finally {unlock(key);}}return failSupplier.getAsLong();}public double tryLockExecute(K key, DoubleSupplier failSupplier, DoubleSupplier supplier) {if (tryLock(key)) {try {return supplier.getAsDouble();} finally {unlock(key);}}return failSupplier.getAsDouble();}public <T> T tryLockExecute(K key, Supplier<T> failSupplier, Supplier<T> supplier) {if (tryLock(key)) {try {return supplier.get();} finally {unlock(key);}}return failSupplier.get();}public boolean tryLockExecute(K key, long timeout, Runnable runnable) {if (tryLock(key, timeout, TimeUnit.MILLISECONDS)) {try {runnable.run();return true;} finally {unlock(key);}}return false;}public boolean tryLockExecute(K key, long timeout, boolean failResult, BooleanSupplier supplier) {if (tryLock(key, timeout, TimeUnit.MILLISECONDS)) {try {return supplier.getAsBoolean();} finally {unlock(key);}}return failResult;}public int tryLockExecute(K key, long timeout, int failResult, IntSupplier supplier) {if (tryLock(key, timeout, TimeUnit.MILLISECONDS)) {try {return supplier.getAsInt();} finally {unlock(key);}}return failResult;}public long tryLockExecute(K key, long timeout, long failResult, LongSupplier supplier) {if (tryLock(key, timeout, TimeUnit.MILLISECONDS)) {try {return supplier.getAsLong();} finally {unlock(key);}}return failResult;}public double tryLockExecute(K key, long timeout, double failResult, DoubleSupplier supplier) {if (tryLock(key, timeout, TimeUnit.MILLISECONDS)) {try {return supplier.getAsDouble();} finally {unlock(key);}}return failResult;}public <T> T tryLockExecute(K key, long timeout, T failResult, Supplier<T> supplier) {if (tryLock(key, timeout, TimeUnit.MILLISECONDS)) {try {return supplier.get();} finally {unlock(key);}}return failResult;}public boolean tryLockExecute(K key, long timeout, BooleanSupplier failSupplier, BooleanSupplier supplier) {if (tryLock(key, timeout, TimeUnit.MILLISECONDS)) {try {return supplier.getAsBoolean();} finally {unlock(key);}}return failSupplier.getAsBoolean();}public int tryLockExecute(K key, long timeout, IntSupplier failSupplier, IntSupplier supplier) {if (tryLock(key, timeout, TimeUnit.MILLISECONDS)) {try {return supplier.getAsInt();} finally {unlock(key);}}return failSupplier.getAsInt();}public long tryLockExecute(K key, long timeout, LongSupplier failSupplier, LongSupplier supplier) {if (tryLock(key, timeout, TimeUnit.MILLISECONDS)) {try {return supplier.getAsLong();} finally {unlock(key);}}return failSupplier.getAsLong();}public double tryLockExecute(K key, long timeout, DoubleSupplier failSupplier, DoubleSupplier supplier) {if (tryLock(key, timeout, TimeUnit.MILLISECONDS)) {try {return supplier.getAsDouble();} finally {unlock(key);}}return failSupplier.getAsDouble();}public <T> T tryLockExecute(K key, long timeout, Supplier<T> failSupplier, Supplier<T> supplier) {if (tryLock(key, timeout, TimeUnit.MILLISECONDS)) {try {return supplier.get();} finally {unlock(key);}}return failSupplier.get();}public boolean tryLockExecute(K key, long timeout, TimeUnit unit, Runnable runnable) {if (tryLock(key, timeout, unit)) {try {runnable.run();return true;} finally {unlock(key);}}return false;}public boolean tryLockExecute(K key, long timeout, TimeUnit unit, boolean failResult, BooleanSupplier supplier) {if (tryLock(key, timeout, unit)) {try {return supplier.getAsBoolean();} finally {unlock(key);}}return failResult;}public int tryLockExecute(K key, long timeout, TimeUnit unit, int failResult, IntSupplier supplier) {if (tryLock(key, timeout, unit)) {try {return supplier.getAsInt();} finally {unlock(key);}}return failResult;}public long tryLockExecute(K key, long timeout, TimeUnit unit, long failResult, LongSupplier supplier) {if (tryLock(key, timeout, unit)) {try {return supplier.getAsLong();} finally {unlock(key);}}return failResult;}public double tryLockExecute(K key, long timeout, TimeUnit unit, double failResult, DoubleSupplier supplier) {if (tryLock(key, timeout, unit)) {try {return supplier.getAsDouble();} finally {unlock(key);}}return failResult;}public <T> T tryLockExecute(K key, long timeout, TimeUnit unit, T failResult, Supplier<T> supplier) {if (tryLock(key, timeout, unit)) {try {return supplier.get();} finally {unlock(key);}}return failResult;}public boolean tryLockExecute(K key, long timeout, TimeUnit unit, BooleanSupplier failSupplier, BooleanSupplier supplier) {if (tryLock(key, timeout, unit)) {try {return supplier.getAsBoolean();} finally {unlock(key);}}return failSupplier.getAsBoolean();}public int tryLockExecute(K key, long timeout, TimeUnit unit, IntSupplier failSupplier, IntSupplier supplier) {if (tryLock(key, timeout, unit)) {try {return supplier.getAsInt();} finally {unlock(key);}}return failSupplier.getAsInt();}public long tryLockExecute(K key, long timeout, TimeUnit unit, LongSupplier failSupplier, LongSupplier supplier) {if (tryLock(key, timeout, unit)) {try {return supplier.getAsLong();} finally {unlock(key);}}return failSupplier.getAsLong();}public double tryLockExecute(K key, long timeout, TimeUnit unit, DoubleSupplier failSupplier, DoubleSupplier supplier) {if (tryLock(key, timeout, unit)) {try {return supplier.getAsDouble();} finally {unlock(key);}}return failSupplier.getAsDouble();}public <T> T tryLockExecute(K key, long timeout, TimeUnit unit, Supplier<T> failSupplier, Supplier<T> supplier) {if (tryLock(key, timeout, unit)) {try {return supplier.get();} finally {unlock(key);}}return failSupplier.get();}static final class Lock extends ReentrantLock {/*** 正在使用或者是准备使用该锁的数量*/int using;/*** 锁的有参构造函数** @param fair 是否公平*/Lock(boolean fair) {super(fair);}}}

都看到这了 点赞+关注一波咯

java key锁 实现对某个key(字符串)加同步锁 带详细注释相关推荐

  1. JAVA之多态万字重要知识点详解(附完整带详细注释的例子代码)

    定义 允许不同类的对象对同一消息作出不同的响应. 分类 1.编译时多态: 也称为设计时多态,通过方法重载实现. 2.运行时多态: 在程序运行时动态决定调用哪个方法. 必要条件 1.满足继承关系. 2. ...

  2. Java多线程系列(六):深入详解Synchronized同步锁的底层实现

    谈到多线程就不得不谈到Synchronized,很多同学只会使用,缺不是很明白整个Synchronized的底层实现原理,这也是面试经常被问到的环节,比如: synchronized的底层实现原理 s ...

  3. 【245期】面试官:同类中两个方法加同步锁,多个线程支持同时访问这两个方法吗?...

    点击上方"Java精选",选择"设为星标" 别问别人为什么,多问自己凭什么! 下方有惊喜,留言必回,有问必答! 每天 08:15 更新文章,每天进步一点点... ...

  4. Java实现对某个值加同步锁

    文章目录 适用场景 一.synchronized(this) 二.synchronized(Object) 三.借用对象加锁 四.最终版 适用场景 在一些场景下,我们需要对某一个值进行加锁,比如支付的 ...

  5. 【Java】Java实现贪吃蛇小游戏(带详细注释)

    源码 源码来源:Java swing 写的贪吃蛇代码200行 前段时间在博客上看到了这段源码,由于自己没有用Java做过小游戏,于是就copy了一下,然后在自己电脑上运行,顺便加上了注释. 代码 gr ...

  6. Java基础 -- 冒泡排序算法(带详细注释)

    冒泡排序的要点: 1.多轮排序,每轮排序中选出最大的元素放在最顶端,并且下次排序不再使用该元素; 2. 使用双for循环,外层for循环控制要排序的次数(轮数), 内层for循环控制当前要排序的元素并 ...

  7. python 线程锁_Python3多线程执行任务含线程同步锁

    Python启动多线程执行任务,用线程锁实现同步分配任务,最后等待所有线程执行完毕#python3多线程演示 import threading import random import time to ...

  8. Java基础类冒泡排序_Java基础 -- 冒泡排序算法(带详细注释)

    冒泡排序的要点: 1.多轮排序,每轮排序中选出最大的元素放在最顶端,并且下次排序不再使用该元素; 2. 使用双for循环,外层for循环控制要排序的次数(轮数), 内层for循环控制当前要排序的元素并 ...

  9. 大规模字符串的近似匹配问题(带详细注释的C++实现)

    //大规模字符串近似匹配程序//程序操作描述:用户首先输入需要放入库中的文本串个数(整数),然后逐一输入放入的各个文本串,然后输入需要进行近似匹配的模式串 // 程序将从文本串库中找出近似度K最高的模 ...

最新文章

  1. 通过iTextSharp为PDF添加带有超链接的Bookmark
  2. 扔掉 Postman,一个工具全部搞定,真香!
  3. 自动规避代码陷阱——自定义Lint规则
  4. ubuntu16.04 xfce4的鼠标主题设置为oxygen-red、修改文件夹背景颜色、两处系统字体设置、右键菜单添加压缩解压选项
  5. opencv中的Mat类型
  6. .net开源框架简介和通用技术选型建议
  7. 第六篇:Spring Boot 访问静态资源
  8. Neural Style Transfer 神经风格迁移详解
  9. 第七届开源操作系统年度技术会议(OS2ATC)盛大开幕,从编译器到软件定义卫星精彩议题大曝光!...
  10. ALinq 让Mysql变得如此简单
  11. Discuz的分页函数
  12. 【2016-2017 ACM-ICPC, Egyptian Collegiate Programming Contest (ECPC 16) A】The game of Osho【SG函数+找规律】
  13. 《HBase权威指南》一3.4 行锁
  14. 编译原理生成中间代码(flex和bison版)
  15. cmd关闭计算机指令,取消CMD自动关机的命令是什么
  16. 单细胞基础教程:跨条件整合分析
  17. (循环串)Periodic Strings UVA - 455
  18. 搜索引擎蜘蛛 ajax,SEO中的搜索引擎蜘蛛技术探析
  19. 偏航角、俯仰角、横滚角的理解
  20. Java---反射机制

热门文章

  1. spring boot 动态切换数据源(数据源信息从数据库中读取)
  2. 小胖机器人宣传语_儿童智能机器人宣传广告词
  3. Excel中如何进行字符串的截取
  4. python分类的英文翻译_分类的英文翻译是什么?
  5. 2020低压电工考试题库及低压电工模拟考试题库
  6. DSN 建立达梦7(DM)连接
  7. Android启动应用时闪一下黑屏
  8. 综述——通过斑马鱼的密集脑回路重建来理解神经计算
  9. 英语学习详细笔记(十八)连接词
  10. Java开发快递物流项目(6)