Java 有类似于 Redis 锁的,只在本应用的锁吗? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
displayabc
V2EX    Java

Java 有类似于 Redis 锁的,只在本应用的锁吗?

  •  
  •   displayabc 2022-06-07 18:20:09 +08:00 5093 次点击
    这是一个创建于 1223 天前的主题,其中的信息可能已经有所发展或是发生改变。

    想要的效果:lock(name, 30s) name 是变量,后边是自动失效时间 不知道有没有类似的成熟库

    第 1 条附言    2022-06-08 10:54:48 +08:00
    感谢大家,目前看到这种方式最简单,也能实现类似效果
    synchronized (name.tostring().intern()) {
    ..
    }
    第 2 条附言    2022-06-08 16:46:35 +08:00
    使用 intern 这种形式,会有个问题,会导致 String 常量池迅速增大,造成性能下降,目前看到的资料是这个常量池很难回收
    28 条回复    2022-07-21 15:33:54 +08:00
    golangLover
        1
    golangLover  
       2022-06-07 18:50:22 +08:00 via Android   4
    guava cache
    sulinwork
        2
    sulinwork  
       2022-06-07 19:26:13 +08:00   2
    都是本地了 为何不直接用 JDK 自带的 Lock 或者 synchronized
    displayabc
        3
    displayabc  
    OP
       2022-06-07 19:45:18 +08:00
    @sulinwork 你肯定没看懂我说什么。。。
    potatowish
        4
    potatowish  
       2022-06-07 21:35:31 +08:00 via iPhone
    可以尝试用 Semaphore 信号量和 DelayQueue 延迟队列自己封装一个
    nl101531
        5
    nl101531  
       2022-06-07 22:01:14 +08:00
    本地锁一般没必要加超时时间,使用完就释放了,没使用完一直持久就好了,所以没怎么见到过你这种需求。

    redis 之所以有超时,是分布式带来的不确定性。
        6
    mosliu  
       2022-06-07 22:37:16 +08:00
    1L 说的应该是对的 记得是用过
    mosliu
    b1t
        7
    b1t  
       2022-06-07 23:24:38 +08:00
    本地缓存?
    rowe
        8
    rowe  
       2022-06-08 00:43:53 +08:00
    redis 加过期时间是因为 在分布式环境加锁风险太大 redis 给出兜底的方案, 单应用加锁随便玩好吗
    chendy
        9
    chendy  
       2022-06-08 07:49:18 +08:00
    Map<String, Lock>
    超时感觉没必要,都写 finally 里了
    redis 超时是怕客户端抽了不释放锁,单机环境没有这个问题
    wanguorui123
        10
    wanguorui123  
       2022-06-08 08:38:12 +08:00
    自旋锁
    mosliu
        11
    mosliu  
       2022-06-08 09:04:34 +08:00   1
    查了下 当时用的
    caffeine 可以 expire
    @haython
    qocja
        12
    qocja  
       2022-06-08 09:33:38 +08:00
    如果你想要锁值的 参考这个文章
    qocja
        13
    qocja  
       2022-06-08 09:33:46 +08:00   1
    huangz003
        14
    huangz003  
       2022-06-08 09:41:17 +08:00
    caffeine > guava cache
    caffeine 是基于 guava cache 开发的,可以构建过期策略,如超时,设置容量大小等方式
    nothingistrue
        15
    nothingistrue  
       2022-06-08 10:26:08 +08:00
    你是想用缓存,还是要线程加锁,还是要利用定时自动解锁做业务逻辑。如果是线程加锁的话,用 await 、wait 、notify 这些线程通信机制来解锁会更有效,实在不行,你还可以用 sleep 。如果是另外两个场景,用 Redis ,比自己搞,更简单还更可靠。
    nekoneko
        16
    nekoneko  
       2022-06-08 10:29:47 +08:00   2
    synchronized(name.intern())
    单应用不需要过期时间
    displayabc
        17
    displayabc  
    OP
       2022-06-08 10:48:45 +08:00
    @nekoneko 还是你这个让人想不到。。。
    ZeawinL
        18
    ZeawinL  
       2022-06-08 11:15:20 +08:00
    #16 楼的方案挺好
    ZeawinL
        19
    ZeawinL  
       2022-06-08 11:19:36 +08:00
    或许也可以使用 ConcurrentHashMap 结合 ReentrantLock 实现.

    ```
    Map<String, ReentrantLock> lockMap = new ConcurrentHashMap<>();
    ReentrantLock lock = lockMap.getOrDefault("key-name", new ReentrantLock());
    lock.tryLock(1, TimeUnit.SECONDS);
    ```

    会不会有什么问题? 坐等大佬指出
    ZeawinL
        20
    ZeawinL  
       2022-06-08 11:34:33 +08:00   1
    纠正一下 #19

    ```
    Map<String, ReentrantLock> lockMap = new ConcurrentHashMap<>();
    ReentrantLock lock = lockMap.computeIfAbsent("key-name", l -> new ReentrantLock());
    lock.tryLock(1, TimeUnit.SECONDS);
    ```
    potatowish
        21
    potatowish  
       2022-06-08 12:20:33 +08:00 via iPhone   1
    @ZeawinL 时间参数是最大等待锁的时间,不是最大持有时间啊
    RedBeanIce
        22
    RedBeanIce  
       2022-06-08 12:29:51 +08:00 via iPhone
    2l 是对的。
    displayabc
        23
    displayabc  
    OP
       2022-06-08 12:56:51 +08:00
    @ZeawinL 锁什么时候释放,Map 什么时候清除这个 key
    姑且按
    lockMap.remove("key-name");
    lock.unlock();
    这种来处理
    当第一个线程 remove 操作之前,有第二个线程来获取锁,获取的还是老的 ReentrantLock ,在 tryLock 阶段,第一个线程 remove 操作了,第三个线程来获取锁,肯定是新的 ReentrantLock
    ZeawinL
        24
    ZeawinL  
       2022-06-08 13:36:57 +08:00 via iPhone
    @potatowish 理解错了,感谢指正
    potatowish
        26
    potatowish  
       2022-06-08 22:27:59 +08:00 via iPhone
    用字符串变量作为锁的名称没有太难吧,用 ConcurrentHashMap 映射一下,或者直接用 intern ,获取常量池引用。

    我觉得重点应该是如何实现锁的过期机制,有没有必要可先放一边。
    NULL2020
        27
    NULL2020  
       2022-07-21 11:01:18 +08:00
    所以,OP 最后使用了什么方法?
    displayabc
        28
    displayabc  
    OP
       2022-07-21 15:33:54 +08:00
    @NULL2020
    synchronized (name.tostring().intern()) {
    ..
    }

    一是因为我的业务可以确定不会有太多字符串,二是可能还没等到常量池太大,就又重新部署一次了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5668 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 01:40 PVG 09:40 LAX 18:40 JFK 21:40
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86