并发和并行的概念:

并发:指在某个时间段内,多任务快速交替处理的能力
并行:指在同一时刻,有多任务在多个处理器上同时执行

并发编程的三大特性

并发场景中多个线程同时工作,存在同步、互斥、分工的问题,所以并发编程的三大特性:
1:可见性
当一个线程修改了共享变量的值,其他线程能够看到修改的值
Java中可见性如何保证?

  • jvm层面 storeLoad内存屏障

以下4种方式去从java代码角度:

  • 通过 volatile 关键字保证可见性。

实现原理:
工作内存修改共享变量后立即同步回主内存;
回写到主内存会导致其他工作内存的缓存无效;
其他工作内存使用时必须从主内存去重新获取

  • 显示调用内存屏障方法 UnsafeFactory.getUnsafe().storeFence()
  • 通过 synchronized关键字。
  • 通过 Lock保证有序性

有时候是Lock锁和volatile联合使用,因为锁的临界区代码可能会发生重排序的情况,多线程的情况下还需要volatile加一层内存屏障,防止重排序,demo是单例模式double-check locking

  • 上下文切换

    1. Thread.yield();<br />2:原子性<br />一个或多个操作,要么全部执行且在执行过程中不被任何因素打断,要么全部不执行<br />3:有序性<br />程序执行的顺序按照编码代码的先后顺序执行。 指令重排导致

JMM

JMM只是一种抽象的概念,定义了共享内存系统中多线程程序读写操作行为的规范,解决由于多线程通过共享内存进行通信时,由于CPU多级缓存、处理器优化、指令重排等导致的内存访问问题。保证了并发场景下的可见性、原子性和有序性.
用JMM屏蔽掉各种硬件和操作系统的内存访问差异,实现Java程序在各种平台下都能达到一致的并发效果。

JMM与硬件内存架构的关系

Java内存模型与硬件内存架构之间存在差异。硬件内存架构没有区分线程栈和堆。对于硬 件,所有的线程栈和堆都分布在主内存中。部分线程栈和堆可能有时候会出现在CPU缓存中和 CPU内部的寄存器中。如下图所示,Java内存模型和计算机硬件内存架构是一个交叉关系
image.png

经典的两个线程修改主存变量flag的例子
线程A while(flag){ } 当flag为true一直占用时间片且循环内部方法的执行时间很短,flag本地内存就不会被淘汰
image.png

public class VisibilityTest {
    //  storeLoad  JVM内存屏障  ---->  (汇编层面指令)  lock; addl $0,0(%%rsp)
    // lock前缀指令不是内存屏障的指令,但是有内存屏障的效果   缓存失效
    private volatile boolean flag = true;
    private Integer count = 0;

    public void refresh() {
        flag = false;
        System.out.println(Thread.currentThread().getName() + "修改flag:"+flag);
    }

    public void load() {
        System.out.println(Thread.currentThread().getName() + "开始执行.....");
        while (flag) {
            //TODO  业务逻辑
            count++;
            //JMM模型    内存模型: 线程间通信有关   共享内存模型
            //没有跳出循环   可见性的问题
            //能够跳出循环   内存屏障
            //UnsafeFactory.getUnsafe().storeFence();
            //能够跳出循环    ?   释放时间片,上下文切换   加载上下文:flag=true
            //Thread.yield();
            //能够跳出循环    内存屏障
            //System.out.println(count);

            //LockSupport.unpark(Thread.currentThread());

            //shortWait(1000000); //1ms
            //shortWait(1000);

//            try {
//                Thread.sleep(1);   //内存屏障
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }

        }
        System.out.println(Thread.currentThread().getName() + "跳出循环: count=" + count);
    }

    public static void main(String[] args) throws InterruptedException {
        VisibilityTest test = new VisibilityTest();

        // 线程threadA模拟数据加载场景
        Thread threadA = new Thread(() -> test.load(), "threadA");
        threadA.start();

        // 让threadA执行一会儿
        Thread.sleep(1000);
        // 线程threadB通过flag控制threadA的执行时间
        Thread threadB = new Thread(() -> test.refresh(), "threadB");
        threadB.start();

    }


    public static void shortWait(long interval) {
        long start = System.nanoTime();
        long end;
        do {
            end = System.nanoTime();
        } while (start + interval >= end);
    }
}