Atomicity in Programming: Concepts, Principles and Java Implementation

Nov 27, 2025 · Programming · 10 views · 7.8

Keywords: Atomicity | Concurrent Programming | Java Memory Model

Abstract: This article provides an in-depth exploration of atomicity in programming, analyzing Java language specifications for atomic operation guarantees and explaining the non-atomic characteristics of long and double types. Through concrete code examples, it demonstrates implementation approaches using volatile keyword, synchronized methods, and AtomicLong class, combining visibility and ordering principles in multithreading environments to deliver comprehensive atomicity solutions. The discussion extends to the importance of atomic operations in concurrent programming and best practices.

Fundamental Concepts of Atomicity

In the realm of concurrent programming, atomicity stands as a critical concept. An atomic operation refers to an indivisible unit of work that either completes entirely or not at all, with no intermediate states observable. From an observer's perspective, atomic operations are perceived as either not yet started or fully completed, never caught in the midst of execution.

Atomicity Guarantees in Java Language Specification

According to the Java Language Specification (JLS 17.4.7), reading or writing variables is atomic by default, with the exception of long and double types. This exception exists because in 32-bit JVMs, 64-bit values for long and double require two separate operations for reading and writing, each handling 32 bits.

Potential Issues with Non-Atomic Operations

Consider the following code example:

long foo = 65465498L;

This assignment operation actually consists of two separate 32-bit write operations at the底层 level. In multithreading environments, if one thread is executing this assignment while another thread simultaneously reads the value of foo, it might observe an intermediate state—an incomplete value where only the first 32 bits or the last 32 bits have been written.

Methods for Achieving Atomicity

Using the volatile Keyword

Declaring a variable as volatile ensures atomic read and write operations:

private volatile long foo;

The volatile keyword not only guarantees visibility (immediate propagation of changes across threads) but also ensures atomicity through memory barriers.

Synchronized Methods

Synchronization mechanisms can ensure atomic access to variables:

public synchronized void setFoo(long value) {
    this.foo = value;
}

public synchronized long getFoo() {
    return this.foo;
}

This approach offers finer control but requires ensuring all variable accesses occur through synchronized methods.

Using AtomicLong Class

Java's concurrency package provides specialized atomic classes:

private AtomicLong foo = new AtomicLong();

AtomicLong employs CAS (Compare-And-Swap) operations to achieve lock-free atomic updates, making it preferable in high-performance scenarios.

Essential Characteristics of Atomicity

From a broader perspective, atomic operations exhibit "one at a time" characteristics. In other programming languages like Swift, non-atomic dictionary operations can lead to similar issues—one thread might read from a dictionary while another modifies it, resulting in inconsistent observations.

Practical Implementation Recommendations

When selecting atomicity implementation strategies, consider specific application contexts:

Understanding the essence of atomicity contributes to writing safer, more reliable concurrent programs.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.