Java并发基础10:原子性操作类的使用

在 java5 以后,我们接触到了线程原子性操作,也就是在修改时我们只需要保证它的那个瞬间是安全的即可,经过相应的包装后可以再处理对象的并发修改,本文总结一下Atomic系列的类的使用方法,其中包含:
| 类型 | Integer | Long | |
| :--------: | :--------:| :--: | :--: |
|基本类型|AtomicInteger|AtomicLong|AtomicBoolean|
|数组类型|AtomicIntegerArray|AtomicLongArray|AtomicReferenceArray|
|属性原子修改器|AtomicIntegerFieldUpdater|AtomicLongFieldUpdater|AtomicReferenceFieldUpdater|

1. 基本类型的使用

首先看一下AtomicInteger的使用,AtomicInteger主要是针对整数的修改的,看一下示例代码:

public class AtomicIntegerDemo { /** * 常见的方法列表 * @see AtomicInteger#get() 直接返回值 * @see AtomicInteger#getAndAdd(int) 增加指定的数据,返回变化前的数据 * @see AtomicInteger#getAndDecrement() 减少1,返回减少前的数据 * @see AtomicInteger#getAndIncrement() 增加1,返回增加前的数据 * @see AtomicInteger#getAndSet(int) 设置指定的数据,返回设置前的数据 * * @see AtomicInteger#addAndGet(int) 增加指定的数据后返回增加后的数据 * @see AtomicInteger#decrementAndGet() 减少1,返回减少后的值 * @see AtomicInteger#incrementAndGet() 增加1,返回增加后的值 * @see AtomicInteger#lazySet(int) 仅仅当get时才会set * * @see AtomicInteger#compareAndSet(int, int) 尝试新增后对比,若增加成功则返回true否则返回false */ public final static AtomicInteger TEST_INTEGER = new AtomicInteger(1); public static void main(String []args) { for(int i = 0 ; i < 10 ; i++) { //开启10个线程 new Thread() { public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } int now = TEST_INTEGER.incrementAndGet(); //自增 System.out.println(Thread.currentThread().getName() + " get value : " + now); } }.start(); } } }

看一下结果:

Thread-3 get value : 4
Thread-7 get value : 5
Thread-9 get value : 9
Thread-4 get value : 6
Thread-0 get value : 3
Thread-1 get value : 8
Thread-5 get value : 11
Thread-8 get value : 7
Thread-2 get value : 10
Thread-6 get value : 2

可以看出,10个线程之间是线程安全的,并没有冲突。也就是说,我们使用原子性操作类去操作基本类型int就可以解决线程安全问题,一个线程在操作的时候,会对其它线程进行排斥,不用我们手动去使用synchronized实现互斥操作了。AtomicLong和AtomicBoolean类似,就不举例子了。

2. 数组类型的使用

下面要开始说Atomic的数组用法,Atomic的数组要求不允许修改长度等,不像集合类那么丰富的操作,不过它可以让数组上每个元素的操作绝对安全的,也就是它细化的力度还是到数组上的元素,做了二次包装,虽然是数组类型的,但是最后还是操作数组中存的数,所以会了上面的基本类型的话,数组类型也很好理解。这里主要看一下AtomicIntegerArray的使用,其它的类似。

public class AtomicIntegerArrayTest { /** * 常见的方法列表 * @see AtomicIntegerArray#addAndGet(int, int) 执行加法,第一个参数为数组的下标,第二个参数为增加的数量,返回增加后的结果 * @see AtomicIntegerArray#compareAndSet(int, int, int) 对比修改,参数1:数组下标,参数2:原始值,参数3,修改目标值,修改成功返回true否则false * @see AtomicIntegerArray#decrementAndGet(int) 参数为数组下标,将数组对应数字减少1,返回减少后的数据 * @see AtomicIntegerArray#incrementAndGet(int) 参数为数组下标,将数组对应数字增加1,返回增加后的数据 * * @see AtomicIntegerArray#getAndAdd(int, int) 和addAndGet类似,区别是返回值是变化前的数据 * @see AtomicIntegerArray#getAndDecrement(int) 和decrementAndGet类似,区别是返回变化前的数据 * @see AtomicIntegerArray#getAndIncrement(int) 和incrementAndGet类似,区别是返回变化前的数据 * @see AtomicIntegerArray#getAndSet(int, int) 将对应下标的数字设置为指定值,第二个参数为设置的值,返回是变化前的数据 */ private final static AtomicIntegerArray ATOMIC_INTEGER_ARRAY = new AtomicIntegerArray(new int[]{1,2,3,4,5,6,7,8,9,10}); public static void main(String []args) throws InterruptedException { Thread []threads = new Thread[10]; for(int i = 0 ; i < 10 ; i++) { final int index = i; final int threadNum = i; threads[i] = new Thread() { public void run() { int result = ATOMIC_INTEGER_ARRAY.addAndGet(index, index + 1); System.out.println("线程编号为:" + threadNum + " , 对应的原始值为:" + (index + 1) + ",增加后的结果为:" + result); } }; threads[i].start(); } for(Thread thread : threads) { thread.join(); } System.out.println("=========================>\n执行已经完成,结果列表:"); for(int i = 0 ; i < ATOMIC_INTEGER_ARRAY.length() ; i++) { System.out.println(ATOMIC_INTEGER_ARRAY.get(i)); } } }

运行结果是给每个数组元素加上相同的值,它们之间互不影响。

3. 作为类属性的使用

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpfpds.html