Java并发编程

xiaoxiao2021-02-28  85

缓存一致性协议

当某个CPU核心写数据时,如果发现其中有变量被其他CUP核心共享,则会通知那个CUP核心将该变量缓存置为无效,如果用到时再去内存重新读取。如此可以保证多个CPU共享同一变量的一致性。

MESI的状态

M(Modifed)  数据有效,CPU的数据被修改了,且与内存中不一致,数据目前只存在于当前CPU的缓存中。E(Exclusive)   数据有效,数据与内存中的数据一致,不与其他CPU缓存同步。S(Shared)      数据有效,数据与内存中的数据一致,且存在于很多CPU缓存中。I(Invalid)      数据无效。

指令重排

为了提高性能,编译器常常会对指令进行重新排序。

编译器优化的重新排序。编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。如定义变量的顺序等。指令集并行的重排序。如果不存在数据依赖性,处理器可以改变单条语句对应机器指令的执行顺序。内存系统的重排序。由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。

并发编程

在并发程序存在共享数据的情况下,必须要保证原子性、可见性及有序性。保证程序的正确运行。 编写线程安全的代码,本质上就是管理对状态(state)的访问,尤其是共享的、可变的状态,即变量。

Java内存模型

这是逻辑上的内存模型。

可见性:

public class ThreadTest extends Thread{ boolean stop = false; int value = 0; public void run() { while(!stop) { value ++; } } public static void main(String[] args) throws InterruptedException { ThreadTest t = new ThreadTest(); t.start(); Thread.sleep(2000); t.stop = true; System.out.println("value=" + t.value); Thread.sleep(2000); System.out.println("value=" + t.value); t.stop(); } }

执行结果:

value=743663561 value=1492400047

t线程每次都是在自己的缓存中读取stop,所以while循环一致都没有停下来,如果在stop变量前加上volatile关键字,那么线程每次调用都会到主存中重新读取。也就是说volatile实现了可见性。

有序性与原子性

public class Singleton { private static volatile Singleton instance; private Singleton(){} public static Singleton getInstancne() { if (instance==null) { synchronized (Singleton.class) { if (instance==null) { //这一步会被分解为三步操作: //1.分配内存 //2.跟instance赋值,指向新创建的对象 //3.调用Singleton的构造函数 //如果不对instance用volatile进行约束, //2和3步可能会被重排,造成某一线程拿到的实例还没有被初始化 instance = new Singleton(); } } } return instance; } }

不允许对 一个volatile变量的赋值操作与其之前的任何读写操作 重新排序, 也不允许将 读取一个volatile变量的操作与其之后的任何读写操作 重新排序。

转载请注明原文地址: https://www.6miu.com/read-75617.html

最新回复(0)