π Simple showcases of java concurrency problems, seeing π is believing π΅
π English Documentation | π δΈζζζ‘£
Simple showcases of Java
concurrency problems, seeing π is believing π΅.
Java
language standard library supports threads, multithreading is heavily used in the language itself (such as GC
) and applications (the server side).Examples of concurrency problems you encountered in development are welcome to provide (submit Issue) or share (pull request after Fork)! π
HashMap
long
variable read invalid value
Demo class NoPublishDemo
.
Set the field stop
to true
in the main
thread to control the exit of the task thread started in main
.
After the main
thread field stop
is true
, the task thread continues to run, that is, no new value has been read in the task thread.
./mvnw compile exec:java -Dexec.mainClass=fucking.concurrency.demo.NoPublishDemo
HashMap
This problem has been explained in many places.
The Demo class HashMapHangDemo
can reproduce this problem.
Two task threads are opened in the main thread to perform the put operation of HashMap
. The main thread does the get operation.
The main thread Block is determined by no continuous output, that is, the endless loop of HashMap
appears.
./mvnw compile exec:java -Dexec.mainClass=fucking.concurrency.demo.HashMapHangDemo
When programming, multiple state records will be required (state can be a POJO
object or int
s, etc.).
It is often seen that the multi-state read and write code is not synchronized, and the person who write it will naturally ignore the issue of thread safety.
Invalid combinations are combinations that have never been set.
The main thread modifies multiple states. For the convenience of checking, each write has a fixed relationship: the second state is twice the value of the first state. Read multiple states in a task thread.
Demo class InvalidCombinationStateDemo
.
The second state read in the task thread is not twice the value of the first state, that is, an invalid value.
./mvnw compile exec:java -Dexec.mainClass=fucking.concurrency.demo.InvalidCombinationStateDemo
long
variable read invalid valueAn invalid value is a value that has never been set.
Reading and writing of long
variables is not atomic and will be divided into two 4-byte operations.
Demo class InvalidLongDemo
.
The main thread modifies the long variable. For the convenience of checking, the upper 4 bytes and the lower 4 bytes of the long value written each time are the same. Read the long variable in the task thread.
In the task thread, a long variable whose upper 4 bytes and lower 4 bytes are different is read, which is an invalid value.
./mvnw compile exec:java -Dexec.mainClass=fucking.concurrency.demo.InvalidLongDemo
Demo class WrongCounterDemo
.
Two task threads are opened in the main thread to execute concurrent incrementing counts. Main thread final result check.
The count value is incorrect.
./mvnw compile exec:java -Dexec.mainClass=fucking.concurrency.demo.WrongCounterDemo
It is common to see synchronization code on a volatile field, and the person who write it will naturally feel that this is safe and correct.
# For problem analysis, see the article Synchronization on mutable fields.
Demo class SynchronizationOnMutableFieldDemo
.
Two task threads are opened in the main thread to execute addListener
. Main thread final result check.
The final count of Listeners is incorrect.
./mvnw compile exec:java -Dexec.mainClass=fucking.concurrency.demo.SynchronizationOnMutableFieldDemo
# For problem analysis, see the article Synchronization on mutable fields
Demo class SymmetricLockDeadlockDemo
.
Two task threads are opened in the main thread for execution.
Task thread deadlocked.
./mvnw compile exec:java -Dexec.mainClass=fucking.concurrency.demo.SymmetricLockDeadlockDemo
# For a problem description, see the paragraph about livelocks in this article
Demo class ReentrantLockLivelockDemo
.
Two task threads are trying to acquire a lock that the other thread holds while holding their own lock.
While the threads are releasing their own lock constantly, they are also re-locking it immediately, denying the other thread a chance to acquire both locks. Since both threads are not blocked from executing but blocked from doing meaningful work, this is a livelock.
./mvnw compile exec:java -Dexec.mainClass=fucking.concurrency.demo.ReentrantLockLivelockDemo