要针对特定的条件进行加锁时,用什么方式是最佳实践?

2020-06-25 16:44:07 +08:00
 abcbuzhiming
大部分数据冲突,往往是用户之间数据冲突,比如秒杀业务,此时对共享资源上一般的锁,或者强迫用户排队,就可以得到解决。

但是有一类情况是这样的,用户和用户之间并没有数据冲突,但是要防止用户“自己抢自己”,比如每日签到奖励这样的业务,1 个用户只有 1 次机会每天,用户和用户之间并没有争抢,我希望根据用户 id 来区分,如果多个线程进入到签到业务(可能是误按,也可能是恶意)时发现用户 id 是同一个,则只会有一个线程进入签到业务处理代码块,其它线程阻塞;但是同时,访问到这块代码时,不是这个用户 id 的线程不受影响,能继续执行
3111 次点击
所在节点    Java
22 条回复
Licsber
2020-06-26 00:59:33 +08:00
为啥不签到只更新今日签到标记
然后用一个单线程在那定时获取已经签到且未发送奖励的
发送完奖励后在这个线程中更新已经发送标记
aguesuka
2020-06-26 09:46:18 +08:00
单应用可以用这个

https://stackoverflow.com/questions/5639870/simple-java-name-based-locks

All those answers I see are way too complicated. Why not simply use:

public void executeInNamedLock(String lockName, Runnable runnable) {
synchronized(lockName.intern()) {
runnable.run();
}
}
The key point is the method intern: it ensures that the String returned is a global unique object, and so it can be used as a vm-instance-wide mutex. All interned Strings are held in a global pool, so that's your static cache you were talking about in your original question. Don't worry about memleaks; those strings will be gc'ed if no other thread references it. Note however, that up to and including Java6 this pool is kept in PermGen space instead of the heap, so you might have to increase it.

There's a problem though if some other code in your vm locks on the same string for completely different reasons, but a) this is very unlikely, and b) you can get around it by introducing namespaces, e.g. executeInNamedLock(this.getClass().getName() + "_" + myLockName);

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/684704

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX