Java's concurrent primitives include synchronized, volatile, atomic classes, CAS and LockSupport, which are the basis for building high concurrency applications. 1. Synchronized ensures atomicity and visibility through monitor locks, and uses memory barriers to prevent instruction reordering; 2. volatile ensures variable visibility and prohibits instruction reordering, suitable for status flags and singleton modes; 3. Atomic classes such as AtomicInteger implement a lock-free mechanism based on CAS, which is suitable for scenarios that read more and write less, but need to pay attention to ABA issues; 4. LockSupport provides underlying support for thread suspension and wake-up, which is more flexible than wait/notify and does not require locks. Understanding these primitives can help improve concurrent programming capabilities and solve practical problems.
Concurrent programming in Java is a piece of content that many developers cannot avoid, especially when building high-performance and highly concurrent applications. Many people have used synchronized
and volatile
, but not many people really understand Java concurrency primitives. This article does not talk about advanced packaging such as thread pool and CompletableFuture, but starts from the bottom layer and talks about several core concurrency primitives we usually use.

What are concurrent primitives?
Concurrent primitives refer to the most basic and lowest-level synchronization mechanism provided by the operating system or language level. In Java, these primitives include, but are not limited to:

-
synchronized
keyword -
volatile
variable - Atomic class under
java.util.concurrent.atomic
package -
LockSupport.park()
/unpark()
- CAS (Compare and Swap)
These mechanisms are not concurrent tool classes (such as ReentrantLock, CountDownLatch), but the basis for building these tools. They are usually closely related to JVM memory model (JMM), affecting variable visibility, execution order and other behaviors.
What exactly did synchronized do?
synchronized
is one of the earliest keywords that Java supports concurrency. It not only guarantees atomicity, but also controls access to critical zones through a built-in monitor lock.

You may know that it can lock, but you don't necessarily understand the memory barrier mechanism behind it:
- Insert Load/Store Barrier when locking to ensure that the latest data is read.
- Insert Store Barrier before unlocking to ensure that the modification is visible to other threads.
- It also prevents instructions from reordering.
For example: multiple threads call a synchronized
method at the same time, only one thread can enter, and the rest of the threads block and wait. Behind this process is actually the state changes of Mark Word in the object header at work.
However, it should be noted that synchronized
performance was indeed worse in the early versions, but after introducing optimizations such as biased locks and lightweight locks from JDK6, its performance has been very good.
volatile: not just "visibility"
volatile
is often used to solve variable visibility problems. For example, if a Boolean flag is not added in a multi-threaded environment, one thread may not be able to see the other thread if it is changed.
But in fact, it has two important features:
- Forbidden to reorder instructions
- Write operation happens-before Read operation
This makes volatile
not only suitable for simple status flags, but also for designs with lock-free structures, such as double check locking in singleton mode.
public class Singleton { private static volatile Singleton instance; public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
volatile
here is to prevent the instruction reordering of new objects from causing other threads to get unconstructed objects.
Atomic classes and CAS: Lockless can be safe
Behind AtomicInteger
, AtomicReference
and other classes is CAS operation, that is, Compare-and-Swap. It is an optimistic locking mechanism suitable for scenarios with less conflict.
CAS has three operands: memory address V, expected value E, and new value U. The value is updated to U only if the value in memory is equal to E.
CAS in Java is implemented through Unsafe
class, and the underlying Unsafe
relies on CPU instructions (such as cmpxchg
on x86).
The advantage of CAS is that there is no thread blocking, and the disadvantage is that ABA problems may occur. You can use AtomicStampedReference
to type timestamp to avoid misjudgment.
Recommended usage:
- Suitable for scenarios where more reads and less competition is not fierce
- Note that too many cycles may cause high CPU usage
- Avoid infinite retry under large amounts of concurrency, which can be combined with spin limiting.
LockSupport: The original means of thread scheduling
If you have looked at the source code of AbstractQueuedSynchronizer
(AQS), you will find that it uses LockSupport.park()
and LockSupport.unpark()
internally to suspend and wake up threads.
The effect of these two methods is very direct:
-
park()
: Let the current thread sleep until it is unpark or interrupted -
unpark(Thread)
: wake up the specified thread
Compared to Object.wait()
and notify()
, it is more flexible, can be called without holding a lock, and does not throw exceptions.
But it is also more prone to errors. For example, calling unpark
twice will only wake up the thread once, and subsequent calling park
will not return immediately.
Basically that's it. Although Java's concurrent primitives seem simple, each have their scope of application and boundary conditions. Understanding their working mechanism will not only help write more efficient concurrent code, but also help troubleshoot deadlocks, memory visibility and other issues.
The above is the detailed content of Deep Dive into Java Concurrency Primitives. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

The difference between HashMap and Hashtable is mainly reflected in thread safety, null value support and performance. 1. In terms of thread safety, Hashtable is thread-safe, and its methods are mostly synchronous methods, while HashMap does not perform synchronization processing, which is not thread-safe; 2. In terms of null value support, HashMap allows one null key and multiple null values, while Hashtable does not allow null keys or values, otherwise a NullPointerException will be thrown; 3. In terms of performance, HashMap is more efficient because there is no synchronization mechanism, and Hashtable has a low locking performance for each operation. It is recommended to use ConcurrentHashMap instead.

StaticmethodsininterfaceswereintroducedinJava8toallowutilityfunctionswithintheinterfaceitself.BeforeJava8,suchfunctionsrequiredseparatehelperclasses,leadingtodisorganizedcode.Now,staticmethodsprovidethreekeybenefits:1)theyenableutilitymethodsdirectly

The JIT compiler optimizes code through four methods: method inline, hot spot detection and compilation, type speculation and devirtualization, and redundant operation elimination. 1. Method inline reduces call overhead and inserts frequently called small methods directly into the call; 2. Hot spot detection and high-frequency code execution and centrally optimize it to save resources; 3. Type speculation collects runtime type information to achieve devirtualization calls, improving efficiency; 4. Redundant operations eliminate useless calculations and inspections based on operational data deletion, enhancing performance.

Instance initialization blocks are used in Java to run initialization logic when creating objects, which are executed before the constructor. It is suitable for scenarios where multiple constructors share initialization code, complex field initialization, or anonymous class initialization scenarios. Unlike static initialization blocks, it is executed every time it is instantiated, while static initialization blocks only run once when the class is loaded.

Factory mode is used to encapsulate object creation logic, making the code more flexible, easy to maintain, and loosely coupled. The core answer is: by centrally managing object creation logic, hiding implementation details, and supporting the creation of multiple related objects. The specific description is as follows: the factory mode handes object creation to a special factory class or method for processing, avoiding the use of newClass() directly; it is suitable for scenarios where multiple types of related objects are created, creation logic may change, and implementation details need to be hidden; for example, in the payment processor, Stripe, PayPal and other instances are created through factories; its implementation includes the object returned by the factory class based on input parameters, and all objects realize a common interface; common variants include simple factories, factory methods and abstract factories, which are suitable for different complexities.

InJava,thefinalkeywordpreventsavariable’svaluefrombeingchangedafterassignment,butitsbehaviordiffersforprimitivesandobjectreferences.Forprimitivevariables,finalmakesthevalueconstant,asinfinalintMAX_SPEED=100;wherereassignmentcausesanerror.Forobjectref

There are two types of conversion: implicit and explicit. 1. Implicit conversion occurs automatically, such as converting int to double; 2. Explicit conversion requires manual operation, such as using (int)myDouble. A case where type conversion is required includes processing user input, mathematical operations, or passing different types of values ??between functions. Issues that need to be noted are: turning floating-point numbers into integers will truncate the fractional part, turning large types into small types may lead to data loss, and some languages ??do not allow direct conversion of specific types. A proper understanding of language conversion rules helps avoid errors.

Synchronizationistheprocessofcoordinatingtwoormorethingstostayaligned,whetherdigitalorphysical.Intechnology,itensuresdataconsistencyacrossdevicesthroughcloudserviceslikeGoogleDriveandiCloud,keepingcontacts,calendarevents,andbookmarksupdated.Outsidete
