volatile关键字及内存可见性
先看一段代码:
package com.java.juc;
public class TestVolatile {
    public static void main(String[] args) {
        ThreadDemo td = new ThreadDemo();
        new Thread(td).start();
        while(true){
            if(td.isFlag()){
                System.out.println("----------------");
                break;
            }
        }
    }
}
class ThreadDemo implements Runnable{
    private boolean flag = false;
    public void run() {
        try {
            Thread.sleep(200);
            flag = true;
            System.out.println("flag= "+ isFlag());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    /**
     * @return the flag
     */
    public boolean isFlag() {
        return flag;
    }
    /**
     * @param flag the flag to set
     */
    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}
运行这段代码,运行的结果只有:
flag= true
这是由于 子线程在操作共享数据时,会将主存总的flag,复制一份到线程的缓存中进行操作,操作完成后会再将数据写到主存中,由于while(true)是一个运行效率非常高的一句代码,而且运行速度非常快,导致主线程再执行循环时没有机会从主存中读取到数据,导致flag的值是主线程最初读到的值,flag = false;
在共享变量上加一个volatile关键字,会解决这个问题
package com.java.juc;
public class TestVolatile {
    public static void main(String[] args) {
        ThreadDemo td = new ThreadDemo();
        new Thread(td).start();
        while(true){
            if(td.isFlag()){
                System.out.println("----------------");
                break;
            }
        }
    }
}
class ThreadDemo implements Runnable{
    private volatile boolean flag = false;
    public void run() {
        try {
            Thread.sleep(200);
            flag = true;
            System.out.println("flag= "+ isFlag());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    /**
     * @return the flag
     */
    public boolean isFlag() {
        return flag;
    }
    /**
     * @param flag the flag to set
     */
    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}
----------------
flag= true
volatile 关键字的作用:当多个线程操作共享数据时,可以保证内存中的数据是可见的。
可以使用内存再来解释,可以认为各个线程操作各自独立缓存中的数据是实时与主存进行同步的,可以理解为多个线程直接在主存中操作数据,而不是在各自的缓存中。
加了volatile后性能还是比什么都不加要讲的,但是比锁的效率要高。
加了volatile之后效率会低在哪?
实际上JVM底层有个优化,叫指令重排序,使用volatile修饰后就不能重排序了。
加锁的效率是最低的(使用synchronized关键字),同步锁会使线程每次从主存中读取数据,但是同步锁的效率很低。有多个线程来访问时先判断锁,如果被其他线程锁挡住,则线程会进入阻塞挂起状态,那得等到下次cpu再次分配任务,才能执行。
当然:volatile和synchronized还是不同的。volatile相较与synchronized是一种较为轻量级的同步策略。
注意:
1. volatile 不具备 "互斥性"
2. volatile 不能保证变量的 "原子性"
volatile关键字及内存可见性的更多相关文章
- volatile关键字与内存可见性
		前言 首先,我们使用多线程的目的在于提高程序的效率,但是如果使用不当,不仅不能提高效率,反而会使程序的性能更低,因为多线程涉及到线程之间的调度.CPU上下文的切换以及包括线程的创建.销毁和同步等等,开 ... 
- volatile关键字与内存可见性&原子变量与CAS算法
		1 .volatile 关键字:当多个线程进行操作共享数据时, 可以保证内存中的数据可见 2 .原子变量:jdk1.5后java.util.concurrent.atomic 包下提供常用的原子变量 ... 
- 详解volatile  关键字与内存可见性
		先来看一个例子: public class VolatileTest { public static void main(String[] args) { T ... 
- 【JUC系列第一篇】-Volatile关键字及内存可见性
		作者:毕来生 微信:878799579 什么是JUC? JUC全称 java.util.concurrent 是在并发编程中很常用的实用工具类 2.Volatile关键字 1.如果一个变量被volat ... 
- java 轻量级同步volatile关键字简介与可见性有序性与synchronized区别 多线程中篇(十二)
		概念 JMM规范解决了线程安全的问题,主要三个方面:原子性.可见性.有序性,借助于synchronized关键字体现,可以有效地保障线程安全(前提是你正确运用) 之前说过,这三个特性并不一定需要全部同 ... 
- 【Java并发编程】6、volatile关键字解析&内存模型&并发编程中三概念
		volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以 ... 
- volatile关键字解析&内存模型&并发编程中三概念
		原文链接: http://www.cnblogs.com/dolphin0520/p/3920373.html volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java5之前,它是一个 ... 
- volotile关键字的内存可见性及重排序
		在理解volotile关键字的作用之前,先粗略解释下内存可见性与指令重排序. 1. 内存可见性 Java内存模型规定,对于多个线程共享的变量,存储在主内存当中,每个线程都有自己独立的工作内存,并且线程 ... 
- Java并发机制(3)--volatile关键字与内存模型
		Java并发编程:volatile关键字解析及内存模型 个人整理自:博客园-海子-http://www.cnblogs.com/dolphin0520/p/3920373.html 1.线程内存模型: ... 
随机推荐
- 三 ip dns等配置
			一IP.端口.协议基本概念 ip的简单概念 互联网上的计算机,都会有一个唯一的32位的地址,ip地址 我们访问服务器,就必须通过ip地址 局域网里也有预留的ip地址 192/10/172.居于王的i ... 
- 20145240 《Java程序设计》第三次实验报告
			20145240 <Java程序设计>第三次实验报告 北京电子科技学院(BESTI)实验报告 课程:Java程序设计 班级:1452 指导教师:娄嘉鹏 实验日期:2016.04.22 实验 ... 
- Objective-C与Swift的混合编程
			Swift 被设计用来无缝兼容 Cocoa 和 Objective-C .在 Swift 中,你可以使用 Objective-C 的 API(包括系统框架和你自定义的代码),你也可以在 Objecti ... 
- Qt开发UDP
			一.单播 1.声明udp对象 QUdpSocket* udpClient: 2.new出对象 udpClient = new QUdpSocket(this); 3.分配本地地址(如果不分配,使用系统 ... 
- Android LCD(三):LCD接口篇【转】
			本文转载自:http://blog.csdn.net/xubin341719/article/details/9177085 关键词:Android LCD控制器 Framebuffer PWM 平 ... 
- redis中文文档
			phpredis是php的一个扩展,效率是相当高有链表排序功能,对创建内存级的模块业务关系 很有用;以下是redis官方提供的命令使用技巧: 下载地址如下: https://github.com/ow ... 
- linux 上传scp 压缩tar命令
			1.Linux 上传scp 1)上传文件与文件夹 scp file weblogic@xx.xxx.xxx.xxx:~/songjd/ scp -r filefolder weblogic@xxx.x ... 
- ssm文件上传下载比较详细的案例
			背景:ssm框架 接下来,我会介绍单文件上传,下载,多文件的上传,下载,使用ajax进行文件的上传下载,和普通的表单提交的文件上传下载. 只要做项目,总是少不了文件的操作,好了废话不多说,直接上代码! ... 
- kafka笔记(一)
			1.kafka应用场景 基于流数据的发布订阅消息系统.实时流数据的高效异步通信.基于流数据的高可用分布式存储! 不同的系统之间实时流数据管道; 2.官方一句话概括 kafka是一个分布式流数据平台:可 ... 
- 泛型学习第三天——C#读取数据库返回泛型集合 把DataSet类型转换为List<T>泛型集合
			定义一个类: public class UserInfo { public System.Guid ID { get; set; } public string LoginName ... 
