博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
多线程2:java.util.concurrent.atomic.*
阅读量:4616 次
发布时间:2019-06-09

本文共 3085 字,大约阅读时间需要 10 分钟。

一个没有并发控制的计数器:

public class Counter implements Runnable {	private static int count;		public void run() {		System.out.println(Thread.currentThread().getName() 				+ ":" + (++count));	}		public static void main(String[] args){		Counter counter = new Counter();		Thread t1 = new Thread(counter);		Thread t2 = new Thread(counter);		Thread t3 = new Thread(counter);		Thread t4 = new Thread(counter);		t1.start();		t2.start();		t3.start();		t4.start();	}}

有时运行正常,但是偶尔会出现如下运行结果:

Thread-1:2Thread-0:1Thread-2:3Thread-3:3

这显然和预期结果不太一样,先用javap -verbose命令分析一下这个类,在字节码层面上,++count等价于虚拟机顺次执行如下5条字节码指令(不考虑运行期的优化)

getstatic  获取指定类的静态域,并将其值压入栈顶iconst_1   将int型1推送至栈顶iadd       将栈顶两int型数值相加并将结果压入栈顶dup        复制栈顶数值并将复制值压入栈顶putstatic  为指定类的静态域赋值

当Thread-3线程执行getstatic指令时,Thread-2线程还未执行至iadd指令,故Thread-3线程获取的初始静态域count的值和Thread-2线程一样,都为2

本质原因就是++count虽然只是一行代码,但这一过程并非原子操作

要保证这种类型的原子操作,可以使用java.util.concurrent.atomic包下的类

软件包 java.util.concurrent.atomic 类的小工具包,支持在单个变量上解除锁的线程安全编程。

示例如下:

public class Counter implements Runnable {	private final AtomicInteger count = new AtomicInteger(0);		public void run() {		System.out.println(Thread.currentThread().getName() 				+ ":" + count.incrementAndGet());	}		public static void main(String[] args){		Counter counter = new Counter();		Thread t1 = new Thread(counter);		Thread t2 = new Thread(counter);		Thread t3 = new Thread(counter);		Thread t4 = new Thread(counter);		t1.start();		t2.start();		t3.start();		t4.start();	}}

看看源代码中究竟是如何实现的

private volatile int value;public AtomicInteger(int initialValue) {	value = initialValue;}public final int incrementAndGet() {	for (;;) {		int current = get();		int next = current + 1;		if (compareAndSet(current, next))			return next;	}}/**	* Atomically sets the value to the given updated value	* if the current value {@code ==} the expected value.	*	* @param expect the expected value	* @param update the new value	* @return true if successful. False return indicates that	* the actual value was not equal to the expected value.	*/public final boolean compareAndSet(int expect, int update) {	return unsafe.compareAndSwapInt(this, valueOffset, expect, update);}    public final int get() {  return value;}

是不是和乐观锁很像,如果结果符合预期结果,就将结果返回,否则不断进行重试,并没有进行同步,兼顾了安全性和性能

java.util.concurrent.atomic包下还有很多类,使用这些类可以保证对这些类的诸如“获取-更新”操作是原子性的,从而避发生竞态条件

AtomicBoolean 可以用原子方式更新的 boolean 值。 AtomicInteger 可以用原子方式更新的 int 值。 AtomicIntegerArray 可以用原子方式更新其元素的 int 数组。 AtomicIntegerFieldUpdater
基于反射的实用工具,可以对指定类的指定 volatile int 字段进行原子更新。 AtomicLong 可以用原子方式更新的 long 值。 AtomicLongArray 可以用原子方式更新其元素的 long 数组。 AtomicLongFieldUpdater
基于反射的实用工具,可以对指定类的指定 volatile long 字段进行原子更新。 AtomicMarkableReference
AtomicMarkableReference 维护带有标记位的对象引用,可以原子方式对其进行更新。 AtomicReference
可以用原子方式更新的对象引用。 AtomicReferenceArray
可以用原子方式更新其元素的对象引用数组。 AtomicReferenceFieldUpdater
基于反射的实用工具,可以对指定类的指定 volatile 字段进行原子更新。 AtomicStampedReference
AtomicStampedReference 维护带有整数“标志”的对象引用,可以用原子方式对其进行更新。

转载于:https://www.cnblogs.com/sean-zou/archive/2012/11/20/3710093.html

你可能感兴趣的文章
Spring3升级到Spring4时, 运行时出现找不到MappingJacksonHttpMessageConverter的情况
查看>>
详解缓冲区溢出攻击以及防范方法
查看>>
分布式事务解决方案(一) 2阶段提交 & 3阶段提交 & TCC
查看>>
android之网格布局和线性布局实现注册页面
查看>>
BZOJ 1014: [JSOI2008]火星人prefix( splay + hash )
查看>>
js /jq 写 全选 反选 不选
查看>>
spring + springmvc + jdbc + quartz + maven整合
查看>>
Android EditText 应用小小结
查看>>
关于分布式事务的读书笔记
查看>>
回调函数通俗解析(之前看了很久都不理解,今天终于ok啦)
查看>>
MySQL 事务
查看>>
(原创)c++11改进我们的程序之垃圾回收
查看>>
IDEA插件(Android Studio插件)开发示例代码及bug解决
查看>>
作业三-6
查看>>
Unity3d 脚本与C#Socket服务器传输数据
查看>>
Indy 10 TIdHTTP 乱码问题
查看>>
linux c socket 源码案例
查看>>
Java 理解CPU缓存(CPU Cache)
查看>>
IOS状态栏
查看>>
面向对象与类
查看>>