For simple multi-threaded code, using synchronization is acceptable. However, using synchronization does have a liveness impact, and as a codebase becomes more complex, the likelihood goes up that you will end up with Deadlock, Starvation, or Livelock.
In cases of more complex concurrency, using Atomic Variables is often a better alternative, as it allows an individual variable to be accessed in a thread-safe manner without the overhead of using synchronized methods or code blocks.
Creating an AtomicInteger
type:
AtomicInteger aInt = new AtomicInteger() // Create with default value 0
AtomicInteger aInt = new AtomicInteger(1) // Create with initial value 1
Similarly for other instance types.
AtomicIntegerArray aIntArray = new AtomicIntegerArray(10) // Create array of specific length
AtomicIntegerArray aIntArray = new AtomicIntegerArray(new int[] {1, 2, 3}) // Initialize array with another array
Similarly for other atomic types.
There is a notable exception that there is no float
and double
types. These can be simulated through the use of Float.floatToIntBits(float)
and Float.intBitsToFloat(int)
for float
as well as Double.doubleToLongBits(double)
and Double.longBitsToDouble(long)
for doubles.
If you are willing to use sun.misc.Unsafe
you can use any primitive variable as atomic by using the atomic operation in sun.misc.Unsafe
. All primitive types should be converted or encoded in int or longs to so use it in this way. For more on this see: sun.misc.Unsafe.