JMM(java内存模型)

JMM(Java内存模型Java Memory Model,简称JMM) 本身是一种抽象的概念并不真实存在,它描述的是一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段,静态字段和构成数组对象的元素)的访问方式。

JMM关于同步的规定:
1、线程解锁前,必须把共享变量的值刷新回主内存
2、线程加锁前,必须读取主内存的最新值到自己的工作内存
3、加锁解锁是同一把锁

由于JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存(有些地方称为栈空间),工作内存是每个线程的私有数据区域,而Java内存模型中规定所有变量都存储在主内存,主内存是共享内存区域,所有线程都可以访问,但线程对变量的操作(读取赋值等)必须在工作内存中你那个进行,首先要将变量从主内存拷贝的自己的工作内存空间,然后对变量进行操作,操作完成后再将变量写会主内存,不能直接操作主内存中的变量,各个线程中的工作内存中存储着主内存中的变量副本拷贝,因此不同的线程间无法访问对方的工资内存,线程间的通信(传值)必须通过主内存来完成,其简要访问过程如下图:


image.png
import java.util.concurrent.TimeUnit;

class MyData {
    volatile int number = 0;
//    int number = 0;
    public void addT060(){
        this.number = 60;
    }
}
public class VolatileDemo {
    public static void main(String[] args){
        MyData  myData = new MyData();
        new Thread(()->{
            System.out.println(Thread.currentThread().getName() + "\t start");
            try{ TimeUnit.SECONDS.sleep(3);} catch(InterruptedException e){e.printStackTrace();}
            myData.addT060();
            System.out.println(Thread.currentThread().getName() + "\t updated numer value :"
                    + myData.number);
        },"one").start();
        //此线程为main线程
        while (myData.number == 0){

        }
        System.out.println(Thread.currentThread().getName() + ":over");
    }
}
当 volatile int number = 0时: 
//one    start
//one    updated numer value :60
//main   over
//此处证明了 加了volatile后的保证可见性的效果,当 one 线程开始调用addT060()方法时把 60
//赋值给 number 顺带着 通知其他一起调用 number变量 的线程 number值已经变成60了

当 int number = 0时: 
//one    start
//one    updated numer value :60
//停在while 死循环 不会走下去了 因为 main函数的线程 里的私有数据区域里的number 永远为0

volatile是java虚拟机提供的轻量级的同步机制
1️⃣、保证可见性
2️⃣、不保证原子性
3️⃣、禁止指令重排

JMM三大特性
1️⃣、可见性
2️⃣、原子性
不可分割、完整性,也即某个线程正在做某个具体业务时,中间不可以被加塞或者分割。需要整体完整,要么同时完成,要么同时失败。(数据的完整性)
3️⃣、有序性

CAS算法(Compare-And-Swap)是一种硬件对并发的支持,针对多处理器操作而设计的处理器中的一种特殊指令,用于管理对共享数据的并发访问
算法保证数据的原子性
CAS算法是硬件对于并发操作共享数据的支持
CAS是一种无所的非阻塞算法的实现
CAS包含了三个操作:
内存值V
预估值A
更新值B
当且仅当 V == A时,V = B ,否则将不进行操作。
简单来说这是分两步操作:
第一步读取内存值赋值给V
第二步是同时读取内存值复制给A 并且 判断 V 是否 等于A 等于把B的值赋值到主内存,否则不进行操作

public class TestAtomicDemo{
    public static void main(String[] args){
        AtomicDemo ad = new AtomicDemo();
        for(int i = 0; i < 10; i++){
           new Thread(ad).start();
    }
  }
}
class AtomicDemo implements Runnable{
    private AtomicInteger serialNumber = new AtomicInteger();
    public void run (){
        try{
          Thread.sleep(200);
      }catch(InterruptedException e){
      }
    }
  System.out.println(getSerialNumber());
}

public int getSerialNumber(){
    //获取和自增
    return serialNumber.getAndIncrement();
}

4-CountDownLatch闭锁
java5.0在 java.util.concurrent 包中提供了多种并发容器类来改进同步容器的性能。
CountDownLatch一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
闭锁可以延迟线程的进度直到其到达终止状态,闭锁可以用来确保某些活动直到其他活动都完成才继续执行:
确保某个计算在其需要的所有资源都被初始化之后才继续执行;
确保某个服务在其依赖的所有其他服务都已经启动之后才启动;
等待直到某个操作所有参与者都准备就绪再继续执行

CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待

package src;

import java.util.concurrent.CountDownLatch;

public class TestCountDownLatch {
public static void main(String[] args) {
final CountDownLatch latch = new CountDownLatch(5);
LatchDemo ld = new LatchDemo(latch);
long start = System.currentTimeMillis();
for (int i = 0; i < 5; i++) {
new Thread(ld).start();
}
try {
//等待线程完成
latch.await();
} catch (InterruptedException e) {
}
long end = System.currentTimeMillis();
System.out.println("耗费时间:" + (end - start));
}
}

class LatchDemo implements Runnable {
private CountDownLatch latch;
public LatchDemo(CountDownLatch latch) {
this.latch = latch;
}
@Override
public void run() {
synchronized (this){
try {
for (int i = 0; i < 50000; i++) {
if (i % 2 == 0) {
System.out.println(i);
}
}
} finally {
//递减1
latch.countDown();
}
}
}
}
生产者与消费者模式Sychronized锁

// 生产者和消费者案例
public class TestProductorAndConsumer {
public static void main(String[] args) {
Clerk clerk = new Clerk();
Productor productor = new Productor(clerk);
Consumer consumer = new Consumer(clerk);
new Thread(productor, "生产者A").start();
new Thread(consumer, "消费者B").start();
new Thread(productor, "生产者C").start();
new Thread(consumer, "消费者D").start();
}
}
//店员
class Clerk {
private int product = 0;
//进货
public synchronized void get() { //循环次数:0
while (product >= 10) { //为了避免虚假唤醒问题,应该总是使用在循环中
System.out.println("库存已满,不再进货");
try {
//等待
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//进货库存 + 1
System.out.println(Thread.currentThread().getName() + ":" + ++product);
//唤起
this.notifyAll();
}
//出售
public synchronized void sale() {
while (product <= 0) {
System.out.println("暂无库存,不进行出售");
try {
//等待
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//出售库存 -1
System.out.println(Thread.currentThread().getName() + ":" + --product);
this.notifyAll();
}
}
//生产者
class Productor implements Runnable {
private Clerk clerk;

public Productor(Clerk clerk) {
    this.clerk = clerk;
}
@Override
public void run() {
    for (int i = 0; i < 20; i++) {

// try {
// Thread.sleep(200);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// //
clerk.get();
}
}
}
//消费者
class Consumer implements Runnable {
private Clerk clerk;
public Consumer(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
// 购买
clerk.sale();
}
}
}

CyclicBarrier
CyclicBarrier的字面意思是可循环(Cyclic)使用的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活,线程进入屏障通过CyclicBarrier的await()方法。

Semaphore
信号量主要用于两个目的,一个是用于多个共享资源的互斥使用,另一个用于并发线程数的控制。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容