volatile实现可见性但不保证原子性

volatile关键字:

  • 能够保证volatile变量的可见性
  • 不能保证volatile变量复合操作的原子性

volatile如何实现内存可见性:

深入来说:通过加入内存屏障和禁止重排序优化来实现的。

  • 对volatile变量执行写操作时,会在写操作后加入一条store屏障指令
  • 对volatile变量执行读操作时,会在读操作前加入一条load屏障指令

通俗地讲:volatile变量在每次被线程访问时,都强迫从主内存中重读该变量的值,而当该变量发生变化时,又会强迫线程将最新的值刷新到主内存。这样任何时刻,不同的线程总能看到该变量的最新值。

线程写volatile变量的过程:

  • 改变线程工作内存中volatile变量副本的值
  • 将改变后的副本的值从工作内存刷新到主内存

线程读volatile变量的过程:

  • 从主内存中读取volatile变量的最新值到线程的工作内存中
  • 从工作内存中读取volatile变量的副本

volatile不能保证volatile变量复合操作的原子性:

private int number = 0;
number++; //不是原子操作

它分为三步:
         读取number的值
         将number的值加1
         写入最新的number的值

保证number自增操作的原子性:

  • 使用synchronized关键字
  • 使用ReentrantLock
  • 使用AtomicInteger

使用synchronized关键字

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
* @author InJavaWeTrust
*/
public class TestSyn implements Runnable { private int number = 0; public int getNumber() {
return this.number;
} public void run() {
increase();
} public void increase() {
synchronized (this) {
this.number++;
}
} public static void main(String[] args) {
ExecutorService exec = Executors.newFixedThreadPool(1000);
TestSyn syn = new TestSyn();
for (int i = 0; i < 1000; i++) {
exec.submit(syn);
}
System.out.println("number : " + syn.getNumber());
exec.shutdown();
}
}

使用ReentrantLock

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author InJavaWeTrust
*/
public class TestRee implements Runnable { private Lock lock = new ReentrantLock();
private int number = 0; public int getNumber() {
return this.number;
} public void run() {
increase();
} public void increase() {
lock.lock();
try {
this.number++;
} finally {
lock.unlock();
}
} public static void main(String[] args) {
TestRee ree = new TestRee();
ExecutorService exec = Executors.newFixedThreadPool(1000);
for (int i = 0; i < 1000; i++) {
exec.submit(ree);
}
System.out.println("number : " + ree.getNumber());
exec.shutdown();
}
}

使用AtomicInteger

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger; /**
* @author InJavaWeTrust
*/
public class TestAtomic implements Runnable { private static AtomicInteger number = new AtomicInteger(0); public void run() {
increase();
} public void increase() {
number.getAndAdd(1);
} public static void main(String[] args) {
TestAtomic ato = new TestAtomic();
ExecutorService exec = Executors.newFixedThreadPool(1000);
for (int i = 0; i < 1000; i++) {
exec.submit(ato);
}
System.out.println("number : " + number.get());
exec.shutdown();
}
}

volatile实现可见性但不保证原子性的更多相关文章

  1. Volatile 只保证可见性,并不保证原子性

    [尊重原创,转载请注明出处]http://blog.csdn.net/guyuealian/article/details/52525724   在说明Java多线程内存可见性之前,先来简单了解一下J ...

  2. volatile实现原理--为什么实现了可见性却不能保证原子性

    本篇文章我们来解决一个问题  这也是面试面的比较多的问题,进阶阶段(高级)一般都会问到. volatile变量怎么保证可见性  为什么在并发情况下无法保证原子性? 比较懒了  摘了一段JVM原理的片段 ...

  3. Java并发_volatile实现可见性但不保证原子性

    读后感 介绍了volatile实现可见性的基本原理 介绍了volatile不能实现原子性的示例,volatile复合操作不能实现原子性,读取值后在自增前改值可能被其它线程读取并修改,自增后刷新值可能会 ...

  4. Java线程-volatile不能保证原子性

    下面是一共通过volatile实现原子性的例子: 通过建立100个线程,计算number这个变量最后的结果. package com.Sychronized; public class Volatil ...

  5. Java并发编程之验证volatile不能保证原子性

    Java并发编程之验证volatile不能保证原子性 通过系列文章的学习,凯哥已经介绍了volatile的三大特性.1:保证可见性 2:不保证原子性 3:保证顺序.那么怎么来验证可见性呢?本文凯哥(凯 ...

  6. Volatile不保证原子性(二)

    Volatile不保证原子性 前言 通过前面对JMM的介绍,我们知道,各个线程对主内存中共享变量的操作都是各个线程各自拷贝到自己的工作内存进行操作后在写回到主内存中的. 这就可能存在一个线程AAA修改 ...

  7. 为什么volatile能保证有序性不能保证原子性

    对于内存模型的三大特性:有序性.原子性.可见性. 大家都知道volatile能保证可见性和有序性但是不能保证原子性,但是为什么呢? 一.原子性.有序性.可见性 1.原子性: (1)原子的意思代表着-- ...

  8. CAS (多线程保证原子性)

    面试必问的CAS,你懂了吗? 置顶 2018年03月14日 22:29:19 程序员囧辉 阅读数:29612   版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csd ...

  9. 聊聊高并发(十九)理解并发编程的几种&quot;性&quot; -- 可见性,有序性,原子性

    这篇的主题本应该放在最初的几篇.讨论的是并发编程最基础的几个核心概念.可是这几个概念又牵扯到非常多的实际技术.比方Java内存模型.各种锁的实现,volatile的实现.原子变量等等,每个都可以展开写 ...

随机推荐

  1. Linux学习之CentOS(十九)------linux 下压缩与解压之 tar、gzip、bzip2、zip、rar

    将文件存储到归档文件中或者从归档文件中获取原始文件,以及为文件创建归档文件 tar [option] [modifiers] [file-list] 参数 file-list是tar进行归档和提取的文 ...

  2. jquery easyui datagrid设置行样式 不可删除某行

    rowStyler: function (index,row) { if (parseInt(row.ksrs) > 0) { return 'color:red'; } }, onLoadSu ...

  3. 初识Redis系列之二:安装及简单使用

    仅介绍windows下的安装 一:下载地址:https://github.com/MSOpenTech/redis/releases. Redis 支持 32 位和 64 位.这个需要根据你系统平台的 ...

  4. 628. Maximum Product of Three Numbers

    Given an integer array, find three numbers whose product is maximum and output the maximum product. ...

  5. 关于html+ashx开发中几个问题的解决方法

    在跟html+ashx打交道的园友们肯定会发现,这种模式虽然优美,但在开发中会遇到一些难处理的地方.我也不例外,下面是自己在实际开发中总结出来的几条经验,希望跟大家分享,更希望得到大家的建议和更好的解 ...

  6. 如何改变hr颜色

    html中用css改变颜色,<hr style="border:0;background-color:#ff0000;height:1px;">如果不加border:0 ...

  7. print语句中逗号(,)和反斜杠(\)的区别

    逗号结尾:   禁止输出换行反斜杠结尾:强制输出换行 >>> print ('A','B') #用一个逗号结尾就可以禁止输出换行 A B >>> print ('A ...

  8. PHP Libxml 函数

    PHP Libxml 简介 Libxml 函数和常量与 SimpleXML.XSLT 以及 DOM 函数一起使用. 安装 这些函数需要 Libxml 程序包. 在 xmlsoft.org 下载 PHP ...

  9. SpringMVC之Ajax与Controller交互

    前面学习了拦截器,通过拦截器我们可以拦截请求,做进一步处理之后再往下进行,这里我们使用Ajax的时候会有一个问题就是会把js.css这些静态资源文件也进行了拦截,这样在jsp中就无法引入的静态资源文件 ...

  10. Swift类中如何创建一个对外只读对内可读写的属性

    很简单用private修饰符,后面跟限制关键字set: class Day{ private(set) var rawValue:Int = 0 func showRawValue(){ print( ...