How to add a lock in this situation?

Code like this ...

public void beforeUpdated(Log log){ synchronized(this){ query(log); merge(log); persist(log); } } 

This method works in a multi-thread environment. CRUD magazines should be atomic. But you only need to synchronize the same identifier (log.getUuid ()). If I block the whole operation, it should have had poor results. I just hope that the logs of the same identifier are blocked during an atomic operation. How can I do it? Please help me if you have any ideas, thanks.

+4
source share
3 answers

I have encountered this situation several times. What you need is a singleton LockFactory, which is actually a weak link dictionary for lock objects. the code should look something like this:

 class LockFactory { private LockFactory() {} private LockFactory instance = null; public static LockFactory getInstance() { if (this.instance == null) this.instance = new LockFactory(); return this.instance; } private int _last_check_size = 0; private int _cleanup_size = 1000; private Map<String, WeakReference> weakRefDictionary = new HashMap<String, WeakReference>(); public object getLock(String id) { synchronized(this) { if (!this.weakRefDictionary.containsKey(id)) this.weakRefDictionary.put(id, new WeakReference(null)); Object lock = this.weakRefDictionary.get(id).Target; if (lock == null) { lock = new Object(); this.weakRefDictionary.get(id).Target = lock; } if (this.weakRefDictionary.size() > this._last_check_size + this._cleanup_size) this._do_cleanup(); return lock; } } public void _do_cleanup() { synchronized(this) { Iterator<Map.Entry<String, WeakReference>> iter = this.weakRefDictionary.entrySet().iterator(); while (iter.hasNext()) { Map.Entry<String,WeakReference> entry = iter.next(); if (entry.getValue().get() == null) { iter.remove(); } } this._last_check_size = this.weakRefDictionary.size(); } } } 

Now for use in your case, simply do:

 public void beforeUpdated(Log log){ synchronized(LockFactory.getInstance().getLock(log.getUuid())){ query(log); merge(log); persist(log); } } 
+5
source

You can save a HashMap that maps log identifiers that have been discovered so far to some Object and synchronize with an Object that belongs to the log identifier. Please note that reading and writing to the HashMap must be synchronized across the HashMap itself.

+1
source

One suggestion is to do something like:

 class Log { private static final WeakHashMap<String, Object> LOCKS = new WeakHashMap<String, Object>(); private final String uuid; public Log(String uuid) { this.uuid = uuid; } public Object getLock() { synchronized (LOCKS) { Object lock = LOCKS.get(uuid); if (lock == null) { lock = new Object(); LOCKS.put(uuid, lock); } return lock; } } } 

and use it like:

 public void beforeUpdated(Log log) { synchronized (log.getLock()) { query(log); merge(log); persist(log); } } 

If the bottleneck to capture a lock from a static weak map bothers you, you can try using something like Guava MapMaker to create a parallel weak hash map.

0
source

Source: https://habr.com/ru/post/1382282/


All Articles