前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java多线程之可见性之volatile

Java多线程之可见性之volatile

原创
作者头像
开源日记
修改2021-01-14 10:23:38
3620
修改2021-01-14 10:23:38
举报
文章被收录于专栏:JVMGCJVMGC

可见性

一个线程对主内存的修改可以及时被其它线程观察到

导致共享变量在线程间不可见的原因

  • 线程交叉执行
  • 指令重排序加上线程交叉执行
  • 共享变量更新后的值没有在工作内存与主存间及时更新
  • 保证可见性和原子性

对于可见性Java提供了synchonizedvolatile

volatile

通过加入内存屏障和禁止重排序优化来实现,保证可见性不保证原子性 对volatile变量进行写操作时,会在写操作后加入一条store屏障指令,将工作内存变量值刷新到主内存。

image-20201231215228591
image-20201231215228591

volatile变量进行读操作时,会在读操作前加入一条load屏障指令,从主内存读取共享变量。

image-20201231215256929
image-20201231215256929

通过上面两点,任何时候,不同线程总能看到该变量的最新值.所有的操作都是CPU级别的。

并不是说使用了volatile就线程安全了

代码语言:txt
复制
package com.keytech.task;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;


public class VolatileTest {

    private static Integer clientTotal=5000;
    private static Integer threadTotal=200;
    private static volatile Integer count=0;

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        Semaphore semaphore=new Semaphore(threadTotal);
        for (int i = 0; i < clientTotal; i++) {
            executorService.execute(()->{
                try{
                    semaphore.acquire();
                    update();
                    semaphore.release();

                }catch (Exception e){
                    e.printStackTrace();
                }
            });
        }
        executorService.shutdown();
        System.out.println("count:"+count);
    }

    private static void update(){
        count++;
    }
}

//count:4988

虽然使用了volatile,但是线程不安全。原因:update是非原子性的。

代码语言:txt
复制
 private static void update() {
     count++; //分3步
     //1.取出当前count值
     //2.count + 1
     //3.count 重新写回主存
 }

假设同时有两个线程进行操作,两个线程同时执行到第一步(从内存中读取最新值)得到一样的最新的结果,然后进入第二步(+1操作)并进行第三步(从新写回主存)。尽管第一步获取的值是一样的,但是同时将+1后的操作写回主存,这样就会丢掉某个+1的操作,这样就会出现线程不安全问题

总结

  • volatile进行多线程加是线程不安全的,不适合计数
  • volatile不具备原子性

volatile的使用场景

  • 对变量的写操作不依赖当前值
  • 该变量没有包含在其它变量的不变式子中
  • volatile适合作为状态的标记量
代码语言:txt
复制
volatile boolean flag = false;

//线程1
context = loadContext();
flag = true;

//线程2
while(!flag){
    sleep();
}
todo(context);
wx.jpg
wx.jpg

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 可见性
    • 导致共享变量在线程间不可见的原因
    • volatile
      • 并不是说使用了volatile就线程安全了
        • 总结
        • volatile的使用场景
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档