java中关于AtomicInteger的使用
在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。咳哟参考我之前写的一篇博客http://www.cnblogs.com/sharkli/p/5597148.html,今天偶然发现可以不用synchronized使用AtomicInteger完成同样的功能,具体代码如下,
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
package TestAtomicInteger;import java.util.concurrent.atomic.AtomicInteger;class MyThread implements Runnable {// static int i = 0; static AtomicInteger ai=new AtomicInteger(0); public void run() { for (int m = 0; m < 1000000; m++) { ai.getAndIncrement(); } }};public class TestAtomicInteger { public static void main(String[] args) throws InterruptedException { MyThread mt = new MyThread(); Thread t1 = new Thread(mt); Thread t2 = new Thread(mt); t1.start(); t2.start(); Thread.sleep(500); System.out.println(MyThread.ai.get()); }} |
可以发现结果都是2000000,也就是说AtomicInteger是线程安全的。
值得一看。
这里,我们来看看AtomicInteger是如何使用非阻塞算法来实现并发控制的。
AtomicInteger的关键域只有一下3个:
- // setup to use Unsafe.compareAndSwapInt for updates
- private static final Unsafe unsafe = Unsafe.getUnsafe();
- private static final long valueOffset;
- private volatile int value;
这里, unsafe是java提供的获得对对象内存地址访问的类,注释已经清楚的写出了,它的作用就是在更新操作时提供“比较并替换”的作用。实际上就是AtomicInteger中的一个工具。
valueOffset是用来记录value本身在内存的编译地址的,这个记录,也主要是为了在更新操作在内存中找到value的位置,方便比较。
注意:value是用来存储整数的时间变量,这里被声明为volatile,就是为了保证在更新操作时,当前线程可以拿到value最新的值(并发环境下,value可能已经被其他线程更新了)。
这里,我们以自增的代码为例,可以看到这个并发控制的核心算法:
/**
* Atomically increments by one the current value.
*
* @return the updated value
*/
public final int incrementAndGet() {
for (;;) {
//这里可以拿到value的最新值
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
public final boolean compareAndSet(int expect, int update) {
//使用unsafe的native方法,实现高效的硬件级别CAS
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
好了,看到这个代码,基本上就看到这个类的核心了。相对来说,其实这个类还是比较简单的。可以参考http://hittyt.iteye.com/blog/1130990
from: https://www.cnblogs.com/sharkli/p/5623524.html
java中关于AtomicInteger的使用的更多相关文章
- 如何理解Java中眼花缭乱的各种并发锁?
在互联网公司面试中,很多小伙伴都被问到过关于锁的问题. 今天,我给大家一次性把Java并发锁的全家桶彻底讲明白.包括互斥锁.读写锁.重入锁.公平锁.悲观锁.自旋锁.偏向锁等等等等.视频有点长,大家一定 ...
- Java中AtomicInteger的使用!!!
今天在看Volley的源码的时候,看到里面使用了AtomicInteger这个类,曾经没用过,今天看了一下API学习了一下: 首先介绍一下这个类的用处,这个类主要是用来替换java中的自增和自减操作, ...
- JAVA 中无锁的线程安全整数 AtomicInteger介绍和使用
Java 中无锁的线程安全整数 AtomicInteger,一个提供原子操作的Integer的类.在Java语言中,++i和i++操作并不是线程安全的,在使用的时候, 不可避免的会用到synchron ...
- java中的原子操作类AtomicInteger及其实现原理
/** * 一,AtomicInteger 是如何实现原子操作的呢? * * 我们先来看一下getAndIncrement的源代码: * public final int getAndIncremen ...
- Java中的多线程你只要看这一篇就够了
学习Java的同学注意了!!! 学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:279558494 我们一起学Java! 引 如果对什么是线程.什么是进程仍存有疑惑, ...
- java中关键字volatile的作用
用在多线程,同步变量. 线程为了提高效率,将某成员变量(如A)拷贝了一份(如B),线程中对A的访问其实访问的是B.只在某些动作时才进行A和B的同步.因此存在A和B不一致的情况.volatile就是用来 ...
- Java中怎样创建线程安全的方法
面试问题: 下面的方法是否线程安全?怎样让它成为线程安全的方法? class MyCounter { private static int counter = 0; public static int ...
- JAVA中关于并发的一些理解
一,JAVA线程是如何实现的? 同步,涉及到多线程操作,那在JAVA中线程是如何实现的呢? 操作系统中讲到,线程的实现(线程模型)主要有三种方式: ①使用内核线程实现 ②使用用户线程实现 ③使用用户线 ...
- java编程思想-java中的并发(二)
二.共享受限资源 有了并发就可以同时做多件事情了.但是,两个或多个线程彼此互相干涉的问题也就出现了.如果不防范这种冲突,就可能发生两个线程同时试图访问同一个银行账户,或向同一个打印机打印,改变同一个值 ...
随机推荐
- Oracle ____Undo
什么是回滚和撤销 update emp set sal=4000 where empno=7788 语句执行过程 1 检查empno=7788记录是否在buffer cache ,如果不存在,则读取到 ...
- Java8实战系列一
从java7到java8,最主要的变化可以总结为 □Lambda表达式 □ 方法引用 □流和默认方法 让我们通过一个小例子感受一下 情景 1 集合对象排序 (对list中的苹果按照重量排序) Coll ...
- LeetCode(34):搜索范围
Medium! 题目描述: 给定一个按照升序排列的整数数组 nums,和一个目标值 target.找出给定目标值在数组中的开始位置和结束位置. 你的算法时间复杂度必须是 O(log n) 级别. 如果 ...
- python 全栈开发,Day69(Django的视图层,Django的模板层)
昨日内容回顾 相关命令: 1 创建项目 django-admin startproject 项目名称 2 创建应用 python manage.py startapp app名称 3 启动项目 pyt ...
- ORACLE 计算时间相减间隔
在Oralce中我发现有add_months函数,加天数N可以用如下方法实现,select sysdate+N from dual 在Oralce中我发现有add_months函数,加天数N可以用如下 ...
- JQuery动画详解(四)
一:基本动画show()显示隐藏的匹配元素.这个就是 'show( speed, [callback] )' 无动画的版本.如果选择的元素是可见的,这个方法将不会改变任何东西.无论这个元素是通过hid ...
- 百度未授权使用地图API
百度地图管理员的回复:这是KEY服务升级的问题, 给您造成的不便,非常抱歉.但我们昨日已修复,你可以再审核一番.若不可以,请提供一下您的系统ak,邮箱或qq发送至(wangwenhai@baidu.c ...
- linux 中的./configuration --prefix=安装路径 的用法(指定源码安装方式的安装路基)
源码的安装一般由3个步骤组成:配置(configure).编译(make).安装(make install). Configure是一个可执行脚本,它有很多选项,在待安装的源码路径下使用命令./con ...
- BZOJ1260 [CQOI2007]涂色paint 动态规划
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1260 题意概括 假设你有一条长度为5的木版,初始时没有涂过任何颜色.你希望把它的5个单位长度分别涂 ...
- java构造代码块与静态代码块
一:构造代码块 1.概述 作用:给对象初始化. 优先级:优先于对象的构造函数之前执行. { /*构造代码块的代码*/ } 给所有的对象统一的初始化,而构造函数只是给特定的对象初始化,因为构造函数可以重 ...