问题

在 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. matlab 画二维图与三维图

    二维图 ezplot('sin(x)');%默认范围 ezplot('sin(x)',[-4 4]);%自己设定范围 三维图 ezmesh('x*x+y*y');%默认范围

  2. linux下安装Cmake和Sniffles

    -------------------------------------------------------------------cmake的安装------------------------- ...

  3. ICMP隧道 ptunnle

    通过ICMP echo(ping request)和reply(ping reply)实现隧道 适用于防火墙只允许ping出站流量的环境 支持多并发连接,性能优 支持身份验证 使用时需要root用户 ...

  4. 六、Prototype 原型设计模式

    需求:使用 new 生成实例需要指定类名,在不指定类的情况下生成实例 代码清单: 原型接口 Product: public interface Product extends Cloneable{ v ...

  5. Java 读取Excel 文件内容

    在一个项目中,有一个需求,是把excel文件的内容转换为xml格式展示.在学习如何操作的过程中,首先是如何获取excel文件,其中操作的代码如下: 1.首先是导入需要的 jar, 下载地址:https ...

  6. mysql 5.7.21 主从集群恢复GTID方式(不锁库)

    从库损坏后,进行恢复 1.查看主加标记点 show master status\G 记录下POST的值 2.备注主库数据 mysqldump -u root -p -S /data/mysql/mys ...

  7. 2019年华南理工大学程序设计竞赛(春季赛)-H-Parco_Love_GCD

    题目链接:https://ac.nowcoder.com/acm/contest/625/H 题意:给定n个数(<=1e9)的序列,其中n<=5e5,求该序列所有子序列的对应的gcd对1e ...

  8. Error in building opencv with ffmpeg

    I installed ffmpeg according to this article. ffmpeg installation was ok. Now I build opencv with ff ...

  9. 【转】iOS 自动化性能采集

      前言 对于iOS总体生态是比较封闭的,相比Android没有像adb这种可以查看内存.cpu的命令.在日常做性能测试,需要借助xcode中instruments查看内存.cpu等数据. 但是借助i ...

  10. C++中 top()与pop()

    top()是取出栈顶元素,不会删掉栈里边的元素 pop()是删除栈顶元素.