I would recommend using a library because getting concurrency directly on your own is tough . For example, you can use a parallel card, for example TrieMap . See answer above.
But suppose you want to do this manually for educational purposes. The first step to make the above thread safe is to use an immutable collection. Therefore, instead of
private val myData: Map[String, MyClass2] = new HashMap[String, MyClass2]()
would you use
private var myData = Map.empty[String, MyClass2]
(Although var is present here, it has a smaller mutable state than the version above. In this case, the only mutable thing is the only reference, whereas in the above example the entire collection is modified)
Now you need to deal with var. You must ensure that the update for var in one thread is "visible" on all other threads. Therefore, you should mark the field as @volatile. This would be enough if you have a publish / sign script when recordings are performed from only one thread. But, assuming you want to read and write from different threads, you will need to use synchronization for all write requests.
Clearly, this is enough to guarantee the introduction of a small helper class:
final class SyncronizedRef[T](initial:T) { @volatile private var current = initial def get:T = current def update(f:T=>T) { this synchronized { current = f(current) } } }
With this little helper, the code above can be implemented as follows:
class MyClass { val state = new SyncronizedRef(Map.empty[String, MyClass2]) def someMethod = { state.update(myData => val id = getSomeId if (myData.containsKey(id)) myData - id else { Log.d("123", "Not found!") myData } } def getSomeId =
That would be thread safe for the card. However, whether or not all of this is thread safe depends on what happens in getSomeID.
In general, this way of working with concurrency will work as long as the thing passed for update is a pure function that simply converts the data without any side effects. If your condition is more complex than a single card, it can be quite difficult to write your updates in a purely functional style.
There are still low-level multithreaded primitives in SynchronizedRef, but the logic of your program is completely free of them. You simply describe how the state of your program changes in response to an external input, creating pure functions.
In any case, the best solution for this particular example is simply to use an existing parallel card implementation.