马士兵java架构师

您现在的位置是:java学习笔记 >

java学习笔记

java内存模型的三大特性

2024-04-08 12:11:25java学习笔记 本文浏览次数:0 百度已收录

本 文 目 录

java内存模型的三大特性

在Java的并发编程世界中,内存模型是一个不可或缺的概念。它定义了线程之间如何共享数据,以及在多线程环境下如何保证数据的可见性、原子性和有序性。了解Java内存模型(JMM)对于编写高效且线程安全的代码至关重要。本文将深入探讨JMM的三大特性:原子性、可见性和有序性,并通过代码案例加以阐释。

原子性

定义与目的

原子性是指一个操作要么完全执行,要么完全不执行,不会在执行过程中被其他线程中断的特性【1】。原子性保证了在并发环境下,对共享数据的操作不会因为线程交错执行而导致数据不一致的问题。

核心类与方法

在Java中,java.util.concurrent.atomic包下的原子类提供了原子性操作的支持。例如,AtomicInteger提供了对整数进行原子操作的方法,如incrementAndGet()compareAndSet()

使用场景

当需要对共享资源进行计数或者累加时,原子性操作就显得尤为重要。例如,统计网站访问量或者实现一个线程安全的计数器。

代码案例

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicExample {
    private static final AtomicInteger counter = new AtomicInteger(0);

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(() -> counter.incrementAndGet()).start();
        }

        // 等待所有线程执行完毕
        while (Thread.activeCount() > 1) {
            Thread.yield();
        }

        System.out.println("Final counter value: " + counter.get());
    }
}

可见性

定义与目的

可见性是指当一个线程修改了共享变量的值,其他线程能够立即看到这个改变的特性【1】。在没有可见性保证的情况下,线程可能会读取到过时的值,导致程序逻辑错误。

核心类与方法

volatile关键字是Java中实现可见性的一种机制。当一个变量被声明为volatile,它会告诉JVM,每次访问这个变量时都要从主内存中读取,而不是从线程的工作内存中读取。

使用场景

volatile适用于状态标记、布尔标志等需要立即反映修改的场景。例如,控制线程的运行状态,如Thread对象的isInterrupted()方法。

代码案例

public class VisibilityExample {
    private volatile boolean running = true;

    public void stop() {
        running = false;
    }

    public void doWork() {
        while (running) {
            // 执行任务
        }
    }
}

有序性

定义与目的

有序性是指程序执行的顺序与代码编写的顺序一致【1】。在多线程环境中,由于编译器和处理器可能会进行指令重排序,这可能会导致程序执行顺序与预期不符。JMM通过内存屏障和happens-before原则来保证操作的有序性。

核心类与方法

synchronized关键字和各种锁(如ReentrantLock)可以保证代码块或者方法的执行顺序。此外,java.lang.Long类中的compareAndSwap方法系列也用于保证操作的有序性。

使用场景

在需要确保多个线程按照特定顺序执行操作时,有序性就显得尤为重要。例如,更新多个共享变量的顺序依赖关系。

代码案例

public class OrderlinessExample {
    private int value = 0;
    private boolean flag = true;

    public synchronized void increment() {
        if (flag) {
            value++;
            flag = false;
        }
    }

    public synchronized void decrement() {
        if (!flag) {
            value--;
            flag = true;
        }
    }

    public static void main(String[] args) {
        OrderlinessExample example = new OrderlinessExample();
        Thread t1 = new Thread(example::increment);
        Thread t2 = new Thread(example::decrement);

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final value: " + example.value);
    }
}

特性对比表格

特性 定义 核心机制 使用场景
原子性 操作不可中断 AtomicInteger, AtomicLong 计数器, 累加器
可见性 修改立即可见 volatile关键字 状态标记, 布尔标志
有序性 执行顺序一致 synchronized, 内存屏障 多线程操作顺序依赖

通过上述分析,我们可以看到JMM的三大特性在多线程编程中扮演着至关重要的角色。它们确保了在并发环境下,数据的完整性和程序的正确性。理解并合理运用这些特性,将有助于我们编写出更加健壮和高效的Java程序。