Hello. I have such a problem: In the application, many threads run randomly through MultiValueMap, which uses some Collection as value. These streams take a collection from Map, extract an element from it, remove it from the collection and process it. If the collection is empty, then the flow should submit a task for updating the collection for this key to the spec. pool. This pool contains a single thread that updates collections by key. The problem is that such a situation is possible when several threads take on the same collection one key, it turns out to be empty, and essentially the same task is sent to the update. I want to avoid this. In a nutshell, I would like it to look like this:

Collection coll = myMap.getCollection(key); if(coll.isLocked()) { // ΠšΠΎΠ»Π»Π΅ΠΊΡ†ΠΈΡ Π·Π°Π»ΠΎΡ‡Π΅Π½Π°, ΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ Π΅Ρ‘ Π½Π΅ Ρ‚Ρ€ΠΎΠ³Π°Π΅ΠΌ Π° ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ΠΈΠΌ ΠΊ ΠΊΠΎΠ»Π»Π΅ΠΊΡ†ΠΈΠΈ для Π΄Ρ€ΡƒΠ³ΠΎΠ³ΠΎ ΠΊΠ»ΡŽΡ‡Π° } if(coll.isEmty()) { coll.lock()// Π±Π»ΠΎΠΊΠΈΡ€ΡƒΠ΅ΠΌ ΠΊΠΎΠ»Π»Π΅ΠΊΡ†ΠΈΡŽ Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½ΠΈΠΊΠ°ΠΊΠΎΠΉ Π΄Ρ€ΡƒΠ³ΠΎΠΉ ΠΏΠΎΡ‚ΠΎΠΊ Π½Π΅ ΠΌΠΎΠ³ ΠΊ Π½Π΅ΠΉ //ΠΎΠ±Ρ€Π°Ρ‚ΠΈΡ‚ΡŒΡΡ, ΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ Π½Π΅ ΠΌΠΎΠ³ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ для Π½Π΅ΠΉ isEmpty() ΠΈ Π·Π°ΡΠ°Π±ΠΌΠΈΡ‚ΠΈΡ‚ΡŒ //таск Π½Π° Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ pool.submit(new MyTask(coll)); } 

This will be the case in handler threads. And in the update thread something like that:

 ... //Обносвили ΠΊΠΎΠ»Π»Π΅ΠΊΡ†ΠΈΡŽ coll.unLock(); // Бняли Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²ΠΊΡƒ,Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΏΠΎΡ‚ΠΎΠΊΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ снова ΠΌΠΎΠ³ΡƒΡ‚ ΠΎΠ±Ρ€Π°Ρ‰Π°Ρ‚ΡŒΡΡ ΠΊ ΠΊΠΎΠ»Π»Π΅ΠΊΡ†ΠΈΠΈ 

Question: how to implement such functionality correctly? (inherit from some collection and make the volatile lock flag. somehow very simple) + Considering the specifics of the problem, please advise the collection for the map? Considering that the elements from the collection need to be deleted, somehow I don’t want to use ArrayList for such purposes, due to possible brakes with System.arrayCopy (...)

  • This topic has already been discussed already? <br/> PS: Bridging collection - nicht gut. Not to mention the fact God forbid to inherit a collection. - cy6erGn0m
  • It was discussed. I described the task. But I asked questions on other issues - Vladimir
  • By the way, the code above is still not correct, even if the collection had a lock. - cy6erGn0m 2:51 pm
  • Well, okay. I sketched in a broken text so that the essence of the problem became clearer. Why it is impossible to inherit from the collection? This is the only thing that comes to mind. Inherited from the collection. There you can make the lock flag, and check it in handler threads and set it to false in the update thread. - Vladimir
  • @Vladimir, before this question you did not come across the question. Do you have one handler in the pool for all keys? Or several (for each key one handler) can work in parallel? - avp

1 answer 1

You can do this:

 class SafeCollectionContainer<T> { private final Map < String, T > safeMap = new HashMap < String, T > (); private final Object locker = new Object (); public T safeRead ( final String key ) { synchronized ( locker ) { return safeMap.get ( key ); } } /** * Safely updates collection found by key * * @return result of the update operation */ public boolean safeUpdate ( final String key, final CollectionUpdater < T > updater ) { synchronized ( locker ) { // get item to update final T value = safeMap.get ( key ); if ( null == value ) { return false; } return updater.update ( value ); } } } 

Here, the block is one shared for the entire container, if you need to block each collection separately, you can synchronize by the value itself or store a locker object for each of them.