首页 / JAVA / Java并发编程框架_原子变量
Java并发编程框架_原子变量
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Java并发编程框架_原子变量,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含3613字,纯文字阅读大概需要6分钟。
内容图文
Java多线程Concurrency框架学习系列文章 _4原子变量, 分析过程中的Demo
组合操作,像value++不是作为单个操作来执行的,实际上包含3个步骤:
- 读取当前value值
- 当前value值+1
- 把value新值写入内存
看一个简单的Demo,代码文件
public class AtomicDemo {
public static void main(String [] args) {
int value = 0;
value++;
}
}
使用javap -c xxxx/AtomicDemo.class,查看生成的代码
public class com.chadm.mulitthread.demo.AtomicDemo {
public com.chadm.mulitthread.demo.AtomicDemo();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_0
1: istore_1
2: iinc 1, 1
5: return
}
可以看到value++生成了3条指令。在多线程场景下,使用没有同步保证的复合操作,会出现非预期的问题,如以下Demo,2个线程同时对volatile count进行操作
private static void multiAdd() throws InterruptedException {
for (int t = 0; t < 5; t++) {
count = 0;
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 100000; i++) {
count++;
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 100000; i++) {
count++;
}
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("count value = " + count);
}
}
生成结果如下,每次循环的打印值是不一样的,因为复合操作非原子操作,多个线程同时进行的时候,可能会出现非预期的结果
count value = 107811
count value = 90790
count value = 76627
count value = 88781
count value = 83716
Process finished with exit code 0
解决上面的问题可以有2种方案:
- 使用synchronized 锁
- 使用java.util.concurrent.atomic.*里面的原子类
原子类
java.util.concurrent.atomic.*里面的结构如下:
主要介绍AtomicInteger和AtomicReference
1.AtomicInteger
以 AtomicInteger类为例说明,类的定义说明一个int值可以被原子更新,能保证操作的原子性。
关键属性value保存着AtomicInteger的值,其中volatile保证了可见性
private volatile int value;
关键方法
public final int getAndIncrement()
从此方法的实现来看该类是如何保证变量更新的原子性
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
v = getIntVolatile(o, offset);
} while (!compareAndSwapInt(o, offset, v, v + delta));
return v;
}
可以看到最终实现是使用CAS来保证的,方法的意思:当前值和expected的值是一致的,才把当前值更新为新值x
/**
* Atomically update Java variable to <tt>x</tt> if it is currently
* holding <tt>expected</tt>.
* @return <tt>true</tt> if successful
*/
public final native boolean compareAndSwapInt(Object o, long offset,
int expected,
int x);
2.AtomicReference
AtomicReference类提供了一个可以原子读写的对象引用变量,使用CAS来保证变量更新操作的原子性,多个线程操作后看到的状态是一致的
关键属性为value,保存着对象的引用,volatile保证可见性
private volatile V value;
关键方法compareAndSet可以保证更新变量的原子性:
public final boolean compareAndSet(V expect, V update)
其实现如下,和Integer的类似:
public final boolean compareAndSet(V expect, V update) {
return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}
上面提到的问题,使用原子类来解决,示例代码如下,其中atomicCount为AtomicInteger类型
private static void atomicAdd() throws InterruptedException {
for (int t = 0; t < 5; t++) {
atomicCount.set(0);
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 100000; i++) {
atomicCount.incrementAndGet();
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 100000; i++) {
atomicCount.incrementAndGet();
}
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("atomicCount value = " + atomicCount.get());
}
}
每次循环的打印都是200000
atomicCount value = 200000
atomicCount value = 200000
atomicCount value = 200000
atomicCount value = 200000
atomicCount value = 200000
内容总结
以上是互联网集市为您收集整理的Java并发编程框架_原子变量全部内容,希望文章能够帮你解决Java并发编程框架_原子变量所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。