I'm reading about Java Concurrency from the book "OCP Oracle Certified Associate Java SE 8 Programmer II Study Guide Exam 1Z0-809" by Boyarsky Jeanne, Selikoff Scott. It says that the code snippet below throws ConcurrentModificationException exception because it removed an element from the foodData hashmap while looping over its iterator.
It doesn't explain in details how this works, but it tells that the solution to this problem is using ConcurrentHashMap instead of HashMap. I found it interesting so I dug deeper.
At first, I wrote a program to run the code snippet above and I got the exception's stack trace below.
at java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1494)
at java.base/java.util.HashMap$KeyIterator.next(HashMap.java:1517)
at ConcurrentCollectionTest.main(ConcurrentCollectionTest.java:9)
It shows that the exception was thrown from within the HashIterator.nextNode() method, not the HashMap.remove() method as I thought. And below is the source code.
abstract class HashIterator {
The methods of all classes injava.util.concurrent
and its subpackages extend these guarantees to higher-level synchronization. In particular:
- Actions in a thread prior to placing an object into any concurrent collection happen-before actions subsequent to the access or removal of that element from the collection in another thread.
- Actions in a thread prior to the submission of a
Runnable
to anExecutor
happen-before its execution begins. Similarly forCallables
submitted to anExecutorService
.- Actions taken by the asynchronous computation represented by a
Future
happen-before actions subsequent to the retrieval of the result viaFuture.get()
in another thread.- Actions prior to "releasing" synchronizer methods such as
Lock.unlock
,Semaphore.release
, andCountDownLatch.countDown
happen-before actions subsequent to a successful "acquiring" method such asLock.lock
,Semaphore.acquire
,Condition.await
, andCountDownLatch.await
on the same synchronizer object in another thread.- For each pair of threads that successfully exchange objects via an
Exchanger
, actions prior to theexchange()
in each thread happen-before those subsequent to the correspondingexchange()
in another thread.- Actions prior to calling
CyclicBarrier.await
andPhaser.awaitAdvance
(as well as its variants) happen-before actions performed by the barrier action, and actions performed by the barrier action happen-before actions subsequent to a successful return from the correspondingawait
in other threads.
Happens-before relationship means one thread finishes its execution before another thread starts its execution so there is no memory consistency errors (or race condition).
No comments:
Post a Comment