`

内存可见性

阅读更多
/**
 * 内存可见性——线程A对变量S的修改,线程B不能马上看到,甚至永远看不到
 */
public class VisibilityDemo {
    private static boolean shutdown = false;
    static class HelloThread extends Thread {
        @Override
        public void run() {
            while(!shutdown){
                // do nothing
            }
            System.out.println("exit hello");
        }
    }
    public static void main(String[] args) throws InterruptedException {
        new HelloThread().start();
        Thread.sleep(1000);
        shutdown = true;
        System.out.println("exit main");
    }
}

引用
exit main
卡住



怎么解决这个问题?
  • 1.使用volatile关键字
  • private volatile static boolean shutdown = false;
    /**
     * 加了volatile之后,Java会在操作对应变量时插入特殊的指令,
     * 保证读写到内存最新值,而非缓存的值
     */

    引用
    exit hello
    exit main
  • 2.使用synchronized关键字
  • public static synchronized boolean isShutdown() {
        return shutdown;
    }
    
    while (!isShutdown()) {
    // do nothing
    }
    System.out.println("exit hello");
    

    引用
    exit hello
    exit main
  • 3.显示锁同步
  • static Lock lock = new ReentrantLock();
    public static boolean isShutdown() {
        try {
            lock.lock();
            return shutdown;
        } finally {
            lock.unlock();
        }
    }
    
    while (!isShutdown()) {
    // do nothing
    }
    System.out.println("exit hello");
    

    引用
    exit hello
    exit main



    内存可见性问题:
  • 计算机系统中,除了内存,数据还会被存储在CPU的寄存器以及各级缓存中。
  • 访问一个变量时,可能直接从寄存器或CPU缓存中获取,而不一定到内存中去取。
  • 修改一个变量时,可能是先写到缓存中,稍后才会同步更新到内存中。

  • -->
    单线程没问题, 但多线程,尤其是多CPU情况下,这就是严重问题。

    一个线程对内存的修改,另一个线程看不到。原因:
  • 修改没有及时同步到内存
  • 另一个线程根本就没从内存读
  • 分享到:
    评论

    相关推荐

      Java volatile与AQS锁内存可见性

      从JUC中的AQS引入,讲解Java volatile与AQS锁内存可见性

      Java并发:volatile内存可见性和指令重排

       1、保证内存可见性  2、防止指令重排  此外需注意volatile并不保证操作的原子性。  (一)内存可见性  1 概念  JVM内存模型:主内存和线程独立的工作内存  Java内存模型规定,对于多个线程共享的变量...

      Java并行(3):可见性重访之锁、Volatile与原子变量1

      在Java并发编程中,内存可见性和线程安全是核心议题。本文将探讨三个关键概念:过期数据、锁的可见性以及Volatile关键字的作用。首先,我们来看一下“过期数据”这一问题。 1. 过期数据 在并发环境中,当多个线程...

      深入理解 Java 内存模型

      Java 内存模型(Java Memory Model,简称 JMM)是 Java 平台中关于线程如何访问共享变量的一套规则,它定义了线程之间的内存可见性、数据一致性以及指令重排序等关键概念,对于多线程编程和并发性能优化至关重要。...

      14、深入理解并发可见性、有序性、原子性与JMM内存模型

      深入理解并发可见性、有序性、原子性与JMM内存模型深入理解并发可见性、有序性、原子性与JMM内存模型深入理解并发可见性、有序性、原子性与JMM内存模型深入理解并发可见性、有序性、原子性与JMM内存模型深入理解并发...

      深入理解Java内存模型

      Java内存模型通过控制主内存与每个线程的本地内存之间的交互,为Java程序员提供了内存可见性保证。 在执行程序时,为了提高性能,编译器和处理器会对指令进行重排序。重排序分为编译器优化的重排序、指令级并行的重...

      java并发之内存模型.docx

      JMM通过控制这种交互来保证内存可见性,即当一个线程修改了某个共享变量后,其他线程能够看到这个修改。 内存模型定义了八种原子操作来确保内存交互的正确性: 1. lock(锁定):锁定主内存中的变量,使其成为线程...

      java内存模型

      然而,这种通信并不是直接的,而是隐式的,这可能导致内存可见性问题。 在Java中,实例变量、静态变量和数组元素存储在堆内存中,可供多个线程共享。而局部变量、方法参数和异常处理器参数不参与线程间的共享,因此...

      java内存模型文档

      - 这是判断数据是否存在竞争、是否需要同步的一个依据,规定了内存可见性的顺序。 7. **原子操作与CAS** - 原子操作(如AtomicInteger)在不使用锁的情况下保证了更新操作的原子性。 - CAS(Compare and Swap)...

      深度剖析java内存模型

      JMM通过控制主内存与每个线程的本地内存之间的交互,为Java程序员提供了内存可见性的保证。 JVM对Java内存模型的实现将内存分为两部分:线程栈区和堆区。每个线程拥有自己的线程栈,其中包含了线程执行的方法调用...

      Java 内存模型

      Java内存模型的核心内容涵盖了锁、线程间的交互、内存可见性和顺序一致性等方面。在JSR-133之前的Java内存模型规范中,volatile变量的语义较弱,它们的访问可以自由排序。但在新规范中,volatile变量的语义被加强为...

      深入理解Java内存模型 pdf 超清版

      - 描述了两个操作之间的顺序关系,是JMM保证内存可见性的基础。 - 例如,一个线程初始化一个对象,然后另一个线程访问这个对象,Happens-Before原则确保了初始化操作对其他线程可见。 4. **重排序** - 编译器和...

      java同步和内存模型

      - **内存可见性问题**:不同线程间可能无法正确地看到变量的最新值,导致线程间的数据不一致。 - **并发执行问题**:当一个线程正在执行`set()`方法的同时,另一个线程尝试调用`check()`方法时,可能会导致不可预测...

      《深入理解JAVA内存模型》PDF

      局部变量(Local variables),方法定义参数(java语言规范称之为formal method parameters)和异常处理器参数(exception handler parameters)不会在线程之间共享,它们不会有内存可见性问题,也不受内存模型的...

      3 JMM内存模型.md,学习代码

      JMM的主要目标是解决内存可见性、原子性和有序性问题。内存可见性是指当一个线程修改了共享变量的值时,其他线程能够立即看到这个改变。原子性确保了某个操作不会被其他线程打断,而有序性则限制了编译器和处理器的...

      java内存模型.pdf

      - JSR133:JSR133是Java内存模型的重要修订,旨在修复早期JMM存在的问题,如内存可见性问题,提供更强的内存语义,并提高性能。它引入了对final和synchronized的新规则,以确保正确同步的代码行为明确且直观。 2. ...

    Global site tag (gtag.js) - Google Analytics