Java:在原语上同步?

Out*_*mer 16 java concurrency

在我们的系统中,我们有一个方法,当它使用某个ID调用时会做一些工作:

public void doWork(long id) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

现在,可以针对不同的ID同时完成这项工作,但是如果使用2个线程使用相同的ID调用该方法,则一个线程应该阻塞直到它完成.

最简单的解决方案是将Map从Long ID映射到我们可以锁定的任意对象.我预见到的一个问题是,我们可以在系统中拥有大量的ID,这个地图每天都会不断增长.

理想情况下,我认为我们需要一个系统,我们每个线程都会获取一个锁定对象,在可能的情况下锁定,完成工作,然后发出信号表明我们已完成锁定.如果很明显没有其他人使用这个特定的锁,那么请从锁定图中安全地将其删除以防止内存泄漏.

我想这一定是一个很常见的场景,所以我希望有一个现有的解决方案.有人知道吗?

Jon*_*erg 15

我不久前为自己发明了类似的东西.我将其称为等价类锁,意思是,它锁定了与给定事物相等的所有事物.您可以从我的github获取它,并根据Apache 2许可证使用它,如果您愿意,或者只是阅读并忘记它!

  • 值得每一分钱.;) (2认同)

Joh*_*int 8

您可以尝试使用ReentrantLock,以便拥有一个Map<Long,Lock>.现在在lock.release()之后你可以测试lock.hasQueuedThreads().如果返回false,则可以从Map中删除它.


Boz*_*zho 7

你可以试试下面的小'黑客'

String str = UNIQUE_METHOD_PREFIX + Long.toString(id);
synchornized(str.intern()) { .. }
Run Code Online (Sandbox Code Playgroud)

100%保证返回相同的实例.

UNIQUE_METHOD_PREFIX,可以是硬编码的常数,或者可以使用来获得:

StackTraceElement ste = Thread.currentThread().getStackTrace()[0];
String uniquePrefix = ste.getDeclaringClass() + ":" +ste.getMethodName();
Run Code Online (Sandbox Code Playgroud)

这将保证只在这种精确的方法上发生锁定.那是为了避免死锁.