displayabc
V2EX  ›  Java

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

  •  
  •   displayabc · Jun 7, 2022 · 6197 views
    This topic created in 1612 days ago, the information mentioned may be changed or developed.

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

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

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

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

    会不会有什么问题? 坐等大佬指出
    tty0
    tty0
    Jun 8, 2022❤️1
    20
    纠正一下 #19

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

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

    一是因为我的业务可以确定不会有太多字符串,二是可能还没等到常量池太大,就又重新部署一次了
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   2778 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 66ms · UTC 10:56 · PVG 18:56 · LAX 02:56 · JFK 05:56
    ♥ Do have faith in what you're doing.