问题

在 int i = 0; i = i++; 语句中,i = i++是线程安全的么?如果不安全,请说明上面操作在JVM中的执行过程,为什么不安全?说出JDK中哪个类能达到以上的效果,并且是线程安全而且高效的,简述其原理。

回答

语句 i = i++;不是线程安全的。

该语句执行过程如下,

先把 i 的值取出来放到栈顶,可以理解为引入了一个第三方变量 k,此时,k的值为i,

然后执行自增操作,i的值变为1,

最后执行赋值操作 i = k (自增前的值)

因此执行结束后,i的值还是0.

从上面的分析可知,i = i++语句的执行过程有多个操作组成,不是原子操作,因此不是线程安全的。

在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而java.util.concurrent.AtomicInteger是一个提供原子操作的Integer类,其提供了线程安全且高效的原子操作,是线程安全的。

AtomicInteger类的底层实现原理是利用处理器的CAS操作(Compare And Swap,比较与交换,一种有名的无锁算法)来检测栈中的值是否被其他线程改变,如果被改变则CAS操作失败。这种实现方法在CPU指令级别实现了原子操作,因此,其比使用synchronized来实现同步效率更高。

CAS操作过程都包含三个运算符:内存地址V、期望值E、新值N。当操作的时候,如果地址V上存放的值等于期望值E,则将地址V上的值赋为新值N,否则,不做任何操作,但是要返回原值是多少。这就保证比较和设置这两个动作是原子操作。系统主要利用JNI(Java Native Interface,Java本地接口)来保证这个原子操作,它利用CPU硬件支持来完成,使用硬件提供swap和test_and_set指令,但CPU下同一指令的多个指令周期不可中断,SMP(Symmetric Multi-Processing)中通过锁总线支持这两个指令的原子性。

Java中 i++ 是线程安全的么?为什么?的更多相关文章

  1. Java中的守护线程 & 非守护线程(简介)

    Java中的守护线程 & 非守护线程 守护线程 (Daemon Thread) 非守护线程,又称用户线程(User Thread) 用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守 ...

  2. Java中如何创建线程

    Java中如何创建线程 两种方式:1)继承Thread类:2)实现Runnable接口. 1.继承Thread类 继承Thread类,重写run方法,在run方法中定义需要执行的任务. class M ...

  3. 关于Java中进程和线程的详解

    一.进程:是程序的一次动态执行,它对应着从代码加载,执行至执行完毕的一个完整的过程,是一个动态的实体,它有自己的生命 周期.它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因完成任务而 ...

  4. Java中怎样创建线程安全的方法

    面试问题: 下面的方法是否线程安全?怎样让它成为线程安全的方法? class MyCounter { private static int counter = 0; public static int ...

  5. ThreadLocal,Java中特殊的线程绑定机制

    在DRP项目中,我们使用了ThreadLocal来创建Connection连接,避免了一直以参数的形式将Connection向下传递(传递connection的目的是由于jdbc事务要求确保使用同一个 ...

  6. Java中的守护线程和非守护线程(转载)

    <什么是守护线程,什么是非守护线程> Java有两种Thread:"守护线程Daemon"(守护线程)与"用户线程User"(非守护线程). 用户线 ...

  7. Java中的守护线程

    守护线程的概念 在java中有两种线程,守护线程和非守护线程,其两者并没有本质的区别,唯一的区别就是当前的用户线程退出的时候,若只存在唯一的A线程,若A线程为守护线程,那么JVM将会直接退出,否则JV ...

  8. (转)Java中的守护线程

    Java的守护线程与非守护线程   守护线程与非守护线程 最近在看多线程的Timer章节,发现运用到了守护线程,感觉Java的基础知识还是需要补充. Java分为两种线程:用户线程和守护线程 所谓守护 ...

  9. Java中的守护线程——daemon

    絮叨 Java中有两类线程:User Thread(用户线程).Daemon Thread(守护线程) 定义:守护线程(aka:服务线程),在没有用户线程可服务时会自动离开. 优先级:守护线程的优先级 ...

  10. Java-ThreadLocal,Java中特殊的线程绑定机制

    在DRP项目中,我们使用了ThreadLocal来创建Connection连接,避免了一直以参数的形式将Connection向下传递(传递connection的目的是由于jdbc事务要求确保使用同一个 ...

随机推荐

  1. centos7里面docker不能下载本地源

    报这种错的 编辑这个文件 加上这一段内容 rstart重启,搞定.

  2. scrapy 琐碎的东西

    1.深度指定 DEPTH_LIMIT=1 2.常用命令 scrapy startproject name scrapy genspider name name.com scrapy crawl nam ...

  3. oracle授予调用存储过程权限

    参考 https://blog.csdn.net/h254532693/article/details/45364317 grant execute on PROCEDURENAME to USERN ...

  4. inception+archery SQL审核平台

    关闭防火墙和selinux 宿主机安装mysql,创建archery数据库,并给所有权限,允许远程连接到该数据库 grant all privileges on *.* to 'root'@'%' i ...

  5. openvpn-admin(openvpn web管理 )

    openvpn 两种认证简介: 1.key分发: 在服务器端生成秘钥,然后下载到本地,将服务器端的ca.crt xx.crt xx.key ta.key(如果服务器启用的话需要,未开启的话不需要,功能 ...

  6. empty 与 remove 的区别

    empty()移除指定元素中的所有子节点,拿$("p").empty()来说,他只是把<p>dsfsd</p>中的文本给移除了,而留下 了<p> ...

  7. cf-Global Round2-D. Frets On Fire(二分)

    题目链接:http://codeforces.com/contest/1119/problem/D 题意:给n(<=1e5)个数s[i],i=1..n,(0<=s[i]<=1e18) ...

  8. 第二章 向量(c)无序向量

  9. int 和 Integer 的区别

    1.两个New生成的Integer 永远不相等,因为他们的内存地址不相等 2.如果一个是New生成的Integer 另一个是通过赋值生成的话,如果值相等那么他们相等,因为这时Integer会通过自动拆 ...

  10. 音频播放 音乐 MediaPlayer

    MediaPlayer对象的生命周期如下: Idle 状态:当使用new()方法创建一个MediaPlayer对象或者调用了其reset()方法时,该MediaPlayer对象处于idle状态.这两种 ...