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. display:none

    $("#loadimg").css("display",""); <span id="loadimg"  clas ...

  2. Linux下常用设置文件和文件夹读写权限操作

    1.查看权限 ls -l xxx.xxx (xxx.xxx是文件名)   2.常见权限 -rw------- (600) 只有所有者才有读和写的权限 -rw-r--r-- (644) 只有所有者才有读 ...

  3. Spring + Mybatis 集成原理分析

    由于我之前是写在wizNote上的,迁移过来比较浪费时间,所以,这里我直接贴个图片,PDF文件我上传到百度云盘了,需要的可直接下载. 地址:https://pan.baidu.com/s/12ZJmw ...

  4. C++后台实践:古老的CGI与Web开发

    本文写给C/C++程序猿,也适合其他对历史感兴趣的程序猿 ============================================= 谈到web开发,大家首先想到的PHP.JavaEE ...

  5. 《读书报告 -- Elasticsearch入门 》--简单使用(2)

    <读书报告 – Elasticsearch入门 > ' 第四章 分布式文件存储 这章的主要内容是理解数据如何在分布式系统中存储. 4.1 路由文档到分片 创建一个新文档时,它是如何确定应该 ...

  6. 微信小程序基础之在微信上显示和体验小程序?

    随着小程序正式上线,用户现在可以通过二维码.搜索等方式体验到开发者们开发的小程序了. 用户只要将微信更新至最新版本,体验过小程序后,便可在发现页面看到小程序TAB,但微信并不会通过这个地方向用户推荐小 ...

  7. 使用Spring Boot开发Web项目(二)之添加HTTPS支持

    上篇博客使用Spring Boot开发Web项目我们简单介绍了使用如何使用Spring Boot创建一个使用了Thymeleaf模板引擎的Web项目,当然这还远远不够.今天我们再来看看如何给我们的We ...

  8. 初始化openresty开发环境

    参考链接 https://www.digitalocean.com/community/tutorials/initial-server-setup-with-ubuntu-14-04 初始化git ...

  9. BlockingQueue(阻塞队列)详解

    一. 前言 在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全"传输"数据的问题.通过这些高效并且线程安全的队列类,为我们快速搭建高质量 ...

  10. Android开发学习之路--基于vitamio的视频播放器(一)

      之前也试过vitamio这个库,后来不知道被什么事情给耽搁了,就没继续下去.近来觉得视频还是需要学习一下的,谁让直播那么火呢,就想着写一个简单的视频播放的app先吧.好了那就开始吧,暂时取名为JP ...