在我们的系统中,我们有一个方法,当它使用某个ID调用时会做一些工作:
public void doWork(long id) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
现在,可以针对不同的ID同时完成这项工作,但是如果使用2个线程使用相同的ID调用该方法,则一个线程应该阻塞直到它完成.
最简单的解决方案是将Map从Long ID映射到我们可以锁定的任意对象.我预见到的一个问题是,我们可以在系统中拥有大量的ID,这个地图每天都会不断增长.
理想情况下,我认为我们需要一个系统,我们每个线程都会获取一个锁定对象,在可能的情况下锁定,完成工作,然后发出信号表明我们已完成锁定.如果很明显没有其他人使用这个特定的锁,那么请从锁定图中安全地将其删除以防止内存泄漏.
我想这一定是一个很常见的场景,所以我希望有一个现有的解决方案.有人知道吗?
您可以尝试使用ReentrantLock,以便拥有一个Map<Long,Lock>.现在在lock.release()之后你可以测试lock.hasQueuedThreads().如果返回false,则可以从Map中删除它.
你可以试试下面的小'黑客'
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)
这将保证只在这种精确的方法上发生锁定.那是为了避免死锁.