multithreading - In Java, multiple threads want to manipulate one object, how to get one manipulate that and the others wait until the work is done? -
my problem little complicated: have concurrent map, threads want visit , update map, if 2 thread want fetch same entry of map, 1 should first map, update it, , other should wait until entry has been updated , fetch entry. original thought that: can use concurrent map, same key targeting map , use latch value. code like:
private final concurrentmap<long, list<rowkeymap>> targetmap; private final concurrentmap<long, countdownlatch> helpermap; long keymillis; //key countdownlatch restorelatch = helpermap.get(keymillis); if (restorelatch != null) { try { restorelatch.await(); } catch (interruptedexception e) { thread.currentthread().interrupt(); throw new runtimeexception("interrupted trying " + keymillis); } } list<rowkeymap> restoredata = targetmap.get(keymillis); if (restoredata == null) { //find entry should restored, put latch helpermap , restore restorelatch = new countdownlatch(1); countdownlatch existinglatch = helpermap.putifabsent(keymillis, restorelatch); if (existinglatch == null) { microshards = new arraylist<>(count); (int = 0; < count; ++i) { microshards.add(new rowkeymap(some parameters)); } list<rowkeymap> existing = targetmap.putifabsent(keymillis, microshards); if (existing == null) { {do actual restore job here} } else { microshards = existing; } restorelatch.countdown(); restoresbydate.remove(keymillis); } else { // lost race, wait restore task complete , new restoredata try { existinglatch.await(); } catch (interruptedexception e) { thread.currentthread().interrupt(); throw new runtimeexception("interrupted trying " + keymillis); } {get new restoredata} } }
but current version has bug:
- thread executes through first line, gets null restorelatch
- thread b wakes , executes through first line, gets null restorelatch
- thread b continues on following lines, sees existinglatch null
- thread b continues, puts created-but-not-yet-restored-into list restoredata
- thread wakes , executes through, created-but-not-yet-restored-into list restoredata
anyone has ideas solve this? thanks!
so want lock per each map entry. i'm not sure countdownlatch
ideal here, because cannot re-used, , creating new 1 each time complicates problem.
but basic problem not preventing race condition lock itself.
in order that, must first ensure lock object entry exists, , if 2 threads go same entry, they same lock.
you can first creating lock object, use putifabsent
put in lock map:
object entrylock = new object(); object returnedlock = helpermap.putifabsent( keymillis, entrylock ); entrylock = returnedlock == null ? entrylock : returnedlock;
what ensure 2 threads trying access same entry (keymillis
) same lock instance. if thread first run putifabsent
line, new object created in first line going 1 placed in helper map, , it's going null
back, means use object placed in map - entrylock
. thread b comes along , create own entrylock
. when tries putifabsent
line, there object mapped keymillis
, returnedlock
, , that's object use (in case, original new lock created discarded garbage collection).
so whichever order thy putifabsent
line, using same lock instance. next step is:
- lock lock.
- run processing of data in targetmap, creating if doesn't exist, updating if does, etc. time, other threads particular
keymillis
waiting, threads otherkeymillis
don't. - unlock lock. 1 of other threads wait
keymillis
entry lock lock.
to pretty simple:
synchronized(entrylock) { // operations on particular entry }
if need fancier lock facilities use reentrantlock
or cyclicbarrier
. countdownlatch
need replaced new 1 usable, , defeat arrangement above, pretty relies on lock object being same threads.
Comments
Post a Comment