/**
* 内存可见性——线程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情况下,这就是严重问题。
一个线程对内存的修改,另一个线程看不到。原因:
修改没有及时同步到内存
另一个线程根本就没从内存读
分享到:
相关推荐
从JUC中的AQS引入,讲解Java volatile与AQS锁内存可见性
1、保证内存可见性 2、防止指令重排 此外需注意volatile并不保证操作的原子性。 (一)内存可见性 1 概念 JVM内存模型:主内存和线程独立的工作内存 Java内存模型规定,对于多个线程共享的变量...
在Java并发编程中,内存可见性和线程安全是核心议题。本文将探讨三个关键概念:过期数据、锁的可见性以及Volatile关键字的作用。首先,我们来看一下“过期数据”这一问题。 1. 过期数据 在并发环境中,当多个线程...
Java 内存模型(Java Memory Model,简称 JMM)是 Java 平台中关于线程如何访问共享变量的一套规则,它定义了线程之间的内存可见性、数据一致性以及指令重排序等关键概念,对于多线程编程和并发性能优化至关重要。...
深入理解并发可见性、有序性、原子性与JMM内存模型深入理解并发可见性、有序性、原子性与JMM内存模型深入理解并发可见性、有序性、原子性与JMM内存模型深入理解并发可见性、有序性、原子性与JMM内存模型深入理解并发...
Java内存模型通过控制主内存与每个线程的本地内存之间的交互,为Java程序员提供了内存可见性保证。 在执行程序时,为了提高性能,编译器和处理器会对指令进行重排序。重排序分为编译器优化的重排序、指令级并行的重...
JMM通过控制这种交互来保证内存可见性,即当一个线程修改了某个共享变量后,其他线程能够看到这个修改。 内存模型定义了八种原子操作来确保内存交互的正确性: 1. lock(锁定):锁定主内存中的变量,使其成为线程...
然而,这种通信并不是直接的,而是隐式的,这可能导致内存可见性问题。 在Java中,实例变量、静态变量和数组元素存储在堆内存中,可供多个线程共享。而局部变量、方法参数和异常处理器参数不参与线程间的共享,因此...
- 这是判断数据是否存在竞争、是否需要同步的一个依据,规定了内存可见性的顺序。 7. **原子操作与CAS** - 原子操作(如AtomicInteger)在不使用锁的情况下保证了更新操作的原子性。 - CAS(Compare and Swap)...
JMM定义了程序中各个变量的内存可见性、原子性和有序性。在多线程环境中,不同的线程可能会同时访问同一个变量,如果没有适当的内存模型来保证这些变量的正确访问,就可能导致程序的行为不可预测。JMM通过一系列规则...
JMM通过控制主内存与每个线程的本地内存之间的交互,为Java程序员提供了内存可见性的保证。 JVM对Java内存模型的实现将内存分为两部分:线程栈区和堆区。每个线程拥有自己的线程栈,其中包含了线程执行的方法调用...
Java内存模型的核心内容涵盖了锁、线程间的交互、内存可见性和顺序一致性等方面。在JSR-133之前的Java内存模型规范中,volatile变量的语义较弱,它们的访问可以自由排序。但在新规范中,volatile变量的语义被加强为...
内存屏障(Memory Barrier)是一种用于控制指令重排序和内存可见性的机制,保证了内存操作的有序性和一致性。 最后,“happens-before”规则是Java内存模型中定义的关于执行顺序的规则之一。它确保了某些操作在其他...
- 描述了两个操作之间的顺序关系,是JMM保证内存可见性的基础。 - 例如,一个线程初始化一个对象,然后另一个线程访问这个对象,Happens-Before原则确保了初始化操作对其他线程可见。 4. **重排序** - 编译器和...
- **内存可见性问题**:不同线程间可能无法正确地看到变量的最新值,导致线程间的数据不一致。 - **并发执行问题**:当一个线程正在执行`set()`方法的同时,另一个线程尝试调用`check()`方法时,可能会导致不可预测...
局部变量(Local variables),方法定义参数(java语言规范称之为formal method parameters)和异常处理器参数(exception handler parameters)不会在线程之间共享,它们不会有内存可见性问题,也不受内存模型的...
JMM的主要目标是解决内存可见性、原子性和有序性问题。内存可见性是指当一个线程修改了共享变量的值时,其他线程能够立即看到这个改变。原子性确保了某个操作不会被其他线程打断,而有序性则限制了编译器和处理器的...