并发编程 多线程volatile关键字作用 JMM java内存模型

并发编程的3大特性
可见性 有序性 原子性  

volatile 保证了可见性与有序性,但不保证原子性保证原子性需要借助synchroniezed这样的锁机制

java线程内存模型JMM volatile关键字作用:线程之间共享变量副本可见性感知 例如:初始化共享变量flag=flase,b线程改变了共享变量flag=true,这时候a线程不知道flag=true,如果初始化变量flag=flase用volatile关键字修饰,
变成volatile flag=flase,那么这个时候a线程就能知道b线程对共享变量的操作变化
JMM数据原子操作(见图5)
read(读取)从主内存读取数据
load(载入)将主内存读取到的数据写入工作内存
use(使用)将工作内存读取数据来计算
assign(赋值)将计算好的重新赋值到工作内存中
store(存储)将工作内数据写入主内存
write(写入)将store过去变量赋值给主内存的变量
lock(锁定)将主内存的变量加锁,标识线程独占状态
unlock(解锁)将主内存的变量解锁,解锁后其他线程可以锁定该变量.

package com.lidl.com.lidl.web;

public class VolatileVisibilityTest {
    //private static boolean initFlag = false;
    //volatile线程之间可见性 底层c语言 如果不加volatile ==============succes就不会被打印,
    //volatile 保证线程之间共享变量副本的可见性,线程之间不能直接通信 必须通过主内存通信
    private static volatile boolean initFlag = false;
    public static void main(String[] args) throws InterruptedException {
        new  Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("wating data...");
                while (!initFlag){

                }
                System.out.println("==============succes");
            }
        }).start();
        Thread.sleep(2000);
        new  Thread(new Runnable() {
            @Override
            public void run() {
                prepareData();
            }
        }).start();
    }
    public static void prepareData(){
        System.out.println("prepareing data...");
        initFlag = true;
        System.out.println("prepareing end...");
    }
}

电脑cpu多核并发缓存框架 图1,之前直接是cpu连接主内存的 后来为什么中间加入缓存 就是因为cpu速度快 发展快 内存发展慢  速度慢 导致内存速度跟不上cpu速度 所以加上缓存缓冲,多线程图2 类似于图1


刚开始的时候使用总线加锁解决共享变量数据一致性,锁的粒度大 多线程并行效果变成了串行效果

后来改成硬件的mesi缓存协议 会在进入总线写入(回写主内存的时候)前加锁,写入成功解锁

package com.lidl.com.lidl.web;

public class VolatileAtomicTest {
    //public static  int num = 0;
    //volatile不保证原子性
    public static volatile int num = 0;
    public static void increase(){
        num++;
    }

    public static void main(String[] args) throws InterruptedException {
        Thread[] threads = new Thread[10];
        for (int i = 0; i <threads.length ; i++) {
            threads[i]= new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 1000; j++) {
                        increase();
                    }
                }
            });
            threads[i].start();
        }
        for (Thread t:threads) {
            t.join();
        }
        System.out.println(num);//1000*10
        //加volatile 结果可能是小于等于10000
    }
}

 

注意

当第一个线程num++的时候num变成1,这个时候正准备写入总线还未写入的时候第二个线程也做完了num++准备写入总线,这时候2 个线程都lock了,但是只有一个lock有效 另外一个线程的共享变量就会失效在重新从主内存读取  这时候读取的就是最新的数据,但是已经num++过一次了 所以结果就会变得小于10000,所以volatile不保证原子性

package com.lidl.com.lidl.web;

import java.util.*;

public class VolatilesSerialTest {
    //static  int x=0,y=0;
    //volatile指令重排 有序性
    //不加volatile输出的结果可能会是00 01 10 11(11不正常)
    //加入volatile之后多线程的执行就会经过指令重排(cpu会自动做优化) 不出现11的结果程序变的正常
    static volatile int x=0,y=0;

    public static void main(String[] args) throws InterruptedException {
        Set<String> resultSet = new HashSet<>();
        Map<String,Integer> resultMap = new HashMap<>();
        for (int i = 0; i < 1000000; i++) {
            x=0;y=0;
            resultMap.clear();
            Thread one = new Thread(new Runnable() {
                @Override
                public void run() {
                    int a =y;//3然后执行这行
                    x=1;//1先执行这行
                    resultMap.put("a",a);

                }
            });
            Thread othor = new Thread(new Runnable() {
                @Override
                public void run() {
                    int b =x;//4最后执行这行
                    y=1;//2在执行这行就会出现a=1,b=1的情况
                    resultMap.put("b",b);

                }
            });
            one.start();
            othor.start();
            one.join();
            othor.join();
            resultSet.add("a=="+resultMap.get("a")+","+"b==" +resultMap.get("b"));
            System.out.println(resultSet);
        }
        }
}

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值