V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
haython
V2EX  ›  Java

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

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

    想要的效果: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
    haython
        3
    haython  
    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 之所以有超时,是分布式带来的不确定性。
    mosliu
        6
    mosliu  
       2022-06-07 22:37:16 +08:00
    1L 说的应该是对的 记得是用过
    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
    如果你想要锁值的 参考这个文章
    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())
    单应用不需要过期时间
    haython
        17
    haython  
    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 是对的。
    haython
        23
    haython  
    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 最后使用了什么方法?
    haython
        28
    haython  
    OP
       2022-07-21 15:33:54 +08:00
    @NULL2020
    synchronized (name.tostring().intern()) {
    ..
    }

    一是因为我的业务可以确定不会有太多字符串,二是可能还没等到常量池太大,就又重新部署一次了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5600 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 38ms · UTC 06:51 · PVG 14:51 · LAX 22:51 · JFK 01:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.