JVM保证线程安全
Java内存模型中,程序(进程)拥有一块内存空间,可以被所有的线程共享,即MainMemory(主内存);而每个线程又有一块独立的内存空间,即WorkingMemory(工作内存)。普通情况下,当线程需要对某一共享变量进行修改时,通常会进行如下的过程:
1. 从主内存中拷贝变量的一份副本,并装载到工作内存中;
2. 在工作内存中执行代码,修改副本的值;
3. 用工作内存中的副本值更新主存中的相关变量值。
如下图:
所谓“线程安全”,即多个线程同时执行同一段代码时,不会出现不确定的或者与单线程条件下不一致的结果。通常,下列三种条件居其一的并发访问被JVM认为是线程安全的:
1. 有final关键字修饰且已被赋值;
2. 有volatile关键字修饰;
3. 有锁保护(synchronized、ReentrantLock等)。
第1点显而易见,不再赘述。
volatile关键字的作用是告知JVM:它所修饰的域的原子操作都不需要经过线程的工作内存,而直接在主内存中进行修改。这样就保证了线程从主内存中读取(read)它的值的时候,总是最新的。但是,Java中的运算极少是原子的,即便是像++ 这样的一元运算符或者+= 这样的二元运算符都不是原子的,因此volatile关键字修饰的域在多线程环境下依然可能会读写出“脏”数据:它只保证每一步原子操作的线程安全,但不保证整个操作过程的线程安全。也因此,volatile主要被用于变量只有原子操作的场合,如赋值、移位等。
锁,无论是显式(ReentrantLock)还是隐式(synchronized)的同步锁,或是信号量(Semaphore),抑或是阻塞队列(BlockingQueue),还是其它的同步措施(CyclicBarrier、CountDownLatch、wait¬ify等),它们的作用都是一样的,就是保证一个共享变量的副本进入到某个线程的工作内存之后,该共享变量就不再会被其它线程访问到,直到前述过程的第3步执行完成。
线程在有同步锁的情况下访问共享变量的过程如下:
1. 获取同步锁
2. 清空工作内存
3. 从主内存将拷贝变量副本,并装载到工作内存
4. 对副本执行代码
5. 用副本数据更新主内存中的相关变量
6. 释放同步锁
通常,没有获得同步锁的线程将被阻塞,直到它竞争到同步锁。这样,没有获得同步锁的线程不仅不能访问数据,甚至都不能继续运行,于是强迫性地保证了线程安全。也因此,线程安全代码的开销要大于不安全的代码,同步锁的开销也要大于volatile。
JVM保证线程安全的更多相关文章
- JVM 进行线程同步背后的原理
前言 所有的 Java 程序都会被翻译为包含字节码的 class 文件,字节码是 JVM 的机器语言.这篇文章将阐述 JVM 是如何处理线程同步以及相关的字节码. 线程和共享数据 Java 的一个优点 ...
- 在JAVA中ArrayList如何保证线程安全
[b]保证线程安全的三种方法:[/b]不要跨线程访问共享变量使共享变量是final类型的将共享变量的操作加上同步一开始就将类设计成线程安全的, 比在后期重新修复它,更容易.编写多线程程序, 首先保证它 ...
- ASP.NET MVC Filters 4种默认过滤器的使用【附示例】 数据库常见死锁原因及处理 .NET源码中的链表 多线程下C#如何保证线程安全? .net实现支付宝在线支付 彻头彻尾理解单例模式与多线程 App.Config详解及读写操作 判断客户端是iOS还是Android,判断是不是在微信浏览器打开
ASP.NET MVC Filters 4种默认过滤器的使用[附示例] 过滤器(Filters)的出现使得我们可以在ASP.NET MVC程序里更好的控制浏览器请求过来的URL,不是每个请求都会响 ...
- 灵魂拷问:Java对象的内存分配过程是如何保证线程安全的?(阿里面试)
JVM内存结构,是很重要的知识,相信每一个静心准备过面试的程序员都可以清楚的把堆.栈.方法区等介绍的比较清楚. 上图,是一张在作者根据<Java虚拟机规范(Java SE 8)>中描述的J ...
- JAVA | Java对象的内存分配过程是如何保证线程安全的?
JAVA | Java对象的内存分配过程是如何保证线程安全的? 专注于Java领域优质技术,欢迎关注 作者 l Hollis 来源 l Hollis(ID:hollischuang) JVM内存结构, ...
- JVM和线程池
本文链接:https://blog.csdn.net/liuwenliang_002/article/details/90074283 ————————————————版权声明:本文为CSDN博主「3 ...
- Java基础图解,JVM,线程,Spring,TCP,SpringMVC等开发体系图解
Java基础图解,JVM,线程,Spring,TCP,SpringMVC等开发体系图解 1.Java虚拟机运行时数据区图 2. 堆的默认分配图 3.方法区结构图 4.对象的内存布局图 5.对象头的Ma ...
- Java并发编程(二)如何保证线程同时/交替执行
第一篇文章中,我用如何保证线程顺序执行的例子作为Java并发系列的开胃菜.本篇我们依然不会有源码分析,而是用另外两个多线程的例子来引出Java.util.concurrent中的几个并发工具的用法. ...
- EF 保证线程内唯一 上下文的创建
1.ef添加完这个对象,就会自动返回这个对象数据库的内容,比如下面这个表是自增ID 最后打印出来的ID 就是自增的结果 2.lambda 中怎么select * var userInfoList = ...
随机推荐
- 史上最“脑残”的“抢火车票”程序(node.js版)
[背景] 快过年了,我妈一个电话打过来叫我给他买火车票,我到12306一查,硬座和硬卧基本没有了,高铁又太贵. 最后只抢了3张无座票,但是我妈说能不能买有座位的啊,我说没有了啊,我妈:你过两天再帮我看 ...
- 【汇编语言】新手第一步——HelloWorld & A+B
国际惯例,HelloWorld. 这个程序是masm for windows里面的样例程序.按照我自己的理解,对其加上了注释. ;完整段的Hello World程序 DATAS SEGMENT STR ...
- 基于Azure blob storage T级别HBase表恢复
为减少Hbase集群压力,提高性能,我们将HBase库中的数据移到另外的存储,下面记录当我需要对数据进行计算时,数据恢复的过程 目录: Azure storage explorer 工具 数据复制 元 ...
- ubuntu安装jdk的两种方法
方法一: 这种方法比较简单,保证虚拟机网络畅通就可以了 sudo apt-get update sudo apt-get install default-jre sudo apt-get instal ...
- 第13章 MySQL高级编程
1.事务:一个或一系列的查询: 2.使用事务安全的表格类型(通过InnoDB): ①关闭自动提交: set autocommit=0; //若自动提交被打开,须使用如下语句开始一个事务: // st ...
- sql 查询表共多少列
1.oracle: select count(*) from user_tab_cols where table_name='表名';--表名含英文的话应为英文大写字母 2.mysql: select ...
- ECS活动真实IP (前端存在SLB)
log_format main 'realip:$http_x_forwarded_for slbip:$remote_addr-$remote_user [$time_local] "$r ...
- shell中bash的常见命令
shell 在计算机科学中,Shell俗称壳,用来区别Kernel(核) Shell分类:1:图形界面shell:通过提供友好的可视化界面,调用相应应用程序,如windows系列操作系统,Linux系 ...
- 移动端 web开发心得
吐槽:华为p9 内置浏览器就是个渣,各种奇葩的bug,1.如果将一个输入框的最大长度设为4,然后输入4个后,js将输入的值置空,就无法再输入了 手机上浏览器比较蛋疼的是,点击一个输入框,输入法将页面挡 ...
- 关于float和position
在div 块级元素中,一般我们的div块都是流式的,如果你设定一个div,接下来的div就会另起行,也就是块级元素的定义 但是一般排版不是这样的,最典型的应该就是这种布局了,那么中间的那三个div ...