Skip to content

Latest commit

 

History

History
159 lines (110 loc) · 4.31 KB

4.Java内存模型的理解.md

File metadata and controls

159 lines (110 loc) · 4.31 KB

1.Java内存模型

1.1Java内存模型

read、load、use、assign、store、write

public class HelloWorld {
    private int data;

    public void increment() {
        data++;
    }
}
        HelloWorld helloWorld = new HelloWorld();

        new Thread() {
            public void run() {
                helloWorld.increment();
            }
        }.start();

        new Thread() {
            public void run() {
                helloWorld.increment();
            }
        }.start();

Java内存模型

1.2 Java 内存模型的原子性、有序性、可见性

连环炮:Java内存模型 -> 原子性、可见性、有序性 -> volatile -> happens-before / 内存屏障

1.2.1 可见性

new Thead() {
    public void run() {
        data++;
    }
}.start();

new Thread() {
    public void run() {
        while(data == 0) {
            Thread.sleep(100);
        }
    }
}.start();

Java内存模型-不可见性

1.2.2 原子性

Java内存模型

线程1在执行的时候,线程2不可对data进行操作,这个时候就具有原子性。如果两个线程都能对data进行更新,那就不具有原子性。

1.2.3 有序性

flag = false;
// 线程1
prepare(); // 准备资源
flag=true;

// 线程2
while(!flag) {
    Thread.sleep(100);
}
execute(); // 基于准备好的资源执行操作

具有有序性,不会发生指令重拍导致我们的代码异常;不具备有序性,则会发生指令重排。导致代码出现一些问题。

1.3 Volatile关键字的原理

private volatile int data = 0;
new Thead() {
    public void run() {
        data++;
    }
}.start();

new Thread() {
    public void run() {
        while(data == 0) {
            Thread.sleep(100);
        }
    }
}.start();

Volatile关键字原理

public class Kafka {
    private volatile boolean running = true;

    private void shutdown() {
        running = false;
    }

    public static void main(String[] args) {
        // 启动kafka,启动代码,不能直接让他退出
        Kafka kafka = new Kafka();
        while (kafka.running) {
            Thread.sleep(1000);
        }
    }
}

加上volatile之后保证其可见性。

1.4 指令重排以及happens-before原则

volatile关键字和有序性的关系,volatile是如何保证有序性的,如何避免发生指令重排。

Java中有一个happens-before原则:

**1.程序次序规则,**一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作。

2.锁定规则,一个unLock从挨揍先行发生于后面对同一个锁额lock操作。

3.volatile变量规则,对一个volatile变量的写操作先行发生于后面对这个变量的读操作。

4.传递规则,如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C。

5.线程启动规则,对Thread对象的start()方法先行发生于此线程的每一个动作。

6.线程中断规则,对线程interrupt()方法的调用先行发生于被中断线程代码检测到中断事件的发生。

7.线程终结规则,线程中所有的操作都先行发生于线程的终止检测,我们可以通过Threa.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行。

8.对象终结规则,一个对象的初始化完成先行发生于他的finalize()方法的开始。

1.5 volatile底层是如何基于内存屏障保证可见性和有序性的?

1.5.1 volatile + 原子性

不能够保证原子性,虽然有些极端情况有保证原子性的效果。

保证原子性,还是用sychronized,lock,加锁。

1.5.2 内存屏障:禁止指令重排

1.6 指令重排

image-20210311153217682