Java多线程之原子性 volatile、atomicInteger测试
原文链接:http://www.cnblogs.com/zhengbin/p/5653051.html
一、补充概念
1.什么是线程安全性?
《Java Concurrency in Practice》中有提到:当多个线程访问某个类时,这个类始终都能表现出正确的行为,那么就称这个类是线程安全的。
2.Java中的“同步”
Java中的主要同步机制是关键字“synchronized”,它提供了一种独占的加锁方式,但“同步”这个术语还包括volatile类型的变量,显式锁(Explicit Lock)以及原子变量。
2.原子性
原子是世界上的最小单位,具有不可分割性。比如 a=0;(a非long和double类型)这个操作是不可分割的,那么我们说这个操作时原子操作。再比如:a++;这个操作实际是a = a + 1;是可分割的,所以他不是一个原子操作。非原子操作都会存在线程安全问题,需要我们使用同步技术(sychronized)来让它变成一个原子操作。一个操作是原子操作,那么我们称它具有原子性。java的concurrent包下提供了一些原子类,我们可以通过阅读API来了解这些原子类的用法。比如:AtomicInteger、AtomicLong、AtomicReference等。
二、实例源码
1 public class IncrementTestDemo {
2
3 public static int count = 0;
4 public static Counter counter = new Counter();
5 public static AtomicInteger atomicInteger = new AtomicInteger(0);
6 volatile public static int countVolatile = 0;
7
8 public static void main(String[] args) {
9 for (int i = 0; i < 10; i++) {
10 new Thread() {
11 public void run() {
12 for (int j = 0; j < 1000; j++) {
13 count++;
14 counter.increment();
15 atomicInteger.getAndIncrement();
16 countVolatile++;
17 }
18 }
19 }.start();
20 }
21 try {
22 Thread.sleep(3000);
23 } catch (InterruptedException e) {
24 e.printStackTrace();
25 }
26
27 System.out.println("static count: " + count);
28 System.out.println("Counter: " + counter.getValue());
29 System.out.println("AtomicInteger: " + atomicInteger.intValue());
30 System.out.println("countVolatile: " + countVolatile);
31 }
32
33 }
34
35 class Counter {
36 private int value;
37
38 public synchronized int getValue() {
39 return value;
40 }
41
42 public synchronized int increment() {
43 return ++value;
44 }
45
46 public synchronized int decrement() {
47 return --value;
48 }
49 }

输出结果:
static count: 9952
Counter: 10000
AtomicInteger: 10000
countVolatile: 9979
第一行与最后一行,每次运行将得到不同的结果,但是中间两行的结果相同。
通过上面的例子说明,要解决自增操作在多线程环境下线程不安全的问题,可以选择使用Java提供的原子类,或者使用synchronized同步方法。
而通过Volatile关键字,并不能解决非原子操作的线程安全性。Volatile详解
三、Java中的自增原理
虽然递增操作++i是一种紧凑的语法,使其看上去只是一个操作,但这个操作并非原子的,因而它并不会作为一个不可分割的操作来执行。实际上,它包含了三个独立的操作:读取count的值,将值加1,然后将计算结果写入count。这是一个“读取 - 修改 - 写入”的操作序列,并且其结果状态依赖于之前的状态。
下面写一个简单的类,用jdk中的工具javap来反编译Java字节码文件。
/**
* @author zhengbinMac
*/
public class TestDemo {
public static int count; public void code() {
count++;
}
}

localhost:Increment zhengbinMac$ javap -c TestDemo
警告: 二进制文件TestDemo包含Increment.TestDemo
Compiled from "TestDemo.java"
public class Increment.TestDemo {
public static int count; public Increment.TestDemo();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return public void code();
Code:
0: getstatic #2 // Field count:I
3: iconst_1
4: iadd
5: putstatic #2 // Field count:I
8: return
}

如上字节码,我们发现自增操作包括取数(getstatic #2)、加一(iconst_1和iadd)、保存(putstatic #2),并不是我们认为的一条机器指令搞定的。
Java多线程之原子性 volatile、atomicInteger测试的更多相关文章
- Java自增原子性问题(测试Volatile、AtomicInteger)
这是美团一面面试官的一个问题,后来发现这是一道面试常见题,怪自己没有准备充分:i++;在多线程环境下是否存在问题?当时回答存在,接着问,那怎么解决?...好吧,我说加锁或者synchronized同步 ...
- Java多线程系列八——volatile和ThreadLocal
参考资料: http://ifeve.com/java-memory-model-4/ http://www.infoq.com/cn/articles/java-memory-model-1 htt ...
- java多线程4:volatile关键字
上文说到了 synchronized,那么就不得不说下 volatile关键字了,它们两者经常协同处理多线程的安全问题. volatile保证可见性 那么volatile的作用是什么呢? 在jvm运行 ...
- java 多线程11:volatile关键字
直接先举一个例子普通的线程实例变量的非可见性: public class MyThread28 extends Thread { private boolean isRunning = true; p ...
- java多线程中的volatile和synchronized
package com.chzhao; public class Volatiletest extends Thread { private static int count = 0; public ...
- Java多线程 -- 正确使用Volatile变量
Java 语言中的 volatile 变量可以被看作是一种 “程度较轻的 synchronized”:与 synchronized 块相比,volatile 变量所需的编码较少,并且运行时开销也较少, ...
- 彻底弄明白之java多线程中的volatile
一. volatite 简述 Java 语言提供了一种稍弱的同步机制,即 volatile 变量.用来确保将变量的更新操作通知到其他线程,保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新. ...
- java多线程-慎重使用volatile关键字
Java语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量.这两种机制的提出都是为了实现代码线程的安全性.其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而 ...
- Java多线程0:核心理论
并发编程是Java程序员最重要的技能之一,也是最难掌握的一种技能.它要求编程者对计算机最底层的运作原理有深刻的理解,同时要求编程者逻辑清晰.思维缜密,这样才能写出高效.安全.可靠的多线程并发程序.本系 ...
随机推荐
- Linux系统中将普通用户添加到sudoers
我们经常会在普通用户下用到sudo命令,为了不用频繁切换root用户,我们可以将普通用户添加到sudoers里面.Linux默认是没有将用户添加到sudoers列表中的,需要root手动将账户添加到s ...
- 开源项目Bug悬赏任务
导读 2014 年开源加密库 OpenSSL 项目爆出的高危漏洞 Heartblood 让世人意识到一些鲜为人知的开源项目对整个互联网和其它基础设施的完整性和可靠性至关重要,随后 Linux 基金会发 ...
- ingress-nginx 添加https证书
1.配了一个证书,发现报错: kubectl logs ingress-nginx-controller-96fnv -n ingress-nginx unexpected error vali ...
- 关于Http 传输二维json
传输一维的好说 public static String doPost(String url) { String result = new String(); OutputStream out = n ...
- [拍摄]『ROSE 拆解』SONY 摄像机镜头拆解。
镜头是从一部很老的sony摄像机上拆下来的.具体型号记不清了.应该是DCR系列的某个型号.使用Hi8磁带.NNN年前摄像机因为意外进水报废...拆拆去最后只剩下镜头了.镜头总成. 图片:IMG_201 ...
- sql语句常用功能(null值转换为0)
COALESCE(规格,' ') 或者 COALESCE(规格,0) select * from ( ) 客户,() 物料号,p4.name 内部批次,p4.outsidename 外部批次,p1.库 ...
- Codechef MGCHGYM Misha and Gym 容斥、背包、Splay
VJ传送门 简化题意:给定一个长度为\(N\)的数列,\(Q\)个操作: \(1\,x\,a\).将数列中第\(x\)个元素改为\(a\) \(2\,l\,r\).反转子序列\([l,r]\) \(3 ...
- 创建一个宽高成比例的弹性div盒子
这里先提供一种,有更好的方法再补充. demo代码如下: <!DOCTYPE html> <html lang="en"> <head> < ...
- 在oj中Python的循环输入问题解决
在oj中Python的循环输入问题解决 在makefile中定义逗号字符串和空格字符串 在linux服务器上面部署javaweb项目jar包 数据结构与算法之栈(Java与Python实现) 在oj中 ...
- python3 installed 安装 pip3
curl -sS https://bootstrap.pypa.io/get-pip.py | sudo python3