原子操作类

本文整理自Java并发编程

目录

原子更新基本类型

原子更新数组

原子更新引用类型

原子更新字段类


java从1.5开始提供了Atomic包,在Atomic包里一共提供了12个类,属于4种类型的原子更新方式。分别是原子更新基本类型,原子更新数组,原子更新引用原子更新属性。Atomic包里的类基本都是使用Unsafe实现的包装类。

1.7

1.8

原子更新基本类型

使用原子的方式更新基本类型,Atomic包提供了以下3个类。
(1)AtomicBoolean: 原子更新布尔类型。
(2)AtomicInteger: 原子更新整型。
(3)AtomicLong: 原子更新长整型。
以上3个类提供的方法几乎一模一样,以AtomicInteger为例进行详解,AtomicIngeter的常用方法如下:
(1)int addAndGet(int delta): 以原子的方式将输入的数值与实例中的值相加,并返回结果。
(2)boolean compareAndSet(int expect, int update): 如果输入的值等于预期值,则以原子方式将该值设置为输入的值。
(3)int getAndIncrement(): 以原子的方式将当前值加1,注意,这里返回的是自增前的值。
(4)void lazySet(int newValue): 最终会设置成newValue,使用lazySet设置值后,可能导致其他线程在之后的一小段时间内还是可以读到旧的值。
(5)int getAndSet(int newValue): 以原子的方式设置为newValue,并返回旧值。

getAndIncrement实现原子操作原理:

public final int getAndIncrement() {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return current;
        }
}

public final int incrementAndGet() {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return next;
        }
}

public final boolean compareAndSet(int expect,int update){
    return unsafe.compareAndSwapInt(this,valueOffset,expect,uodate);
}

1 for循环里先获得AtomicInteger里存储的值current

2 对当前数值进行+1操作,得到next

3 调用compareAndSet进行原子更新操作(compareAndSet底层使用unsafe.compareAndSwapInt实现)

    3.1 先检查当前数值是否等于current

    3.2 等于意味着AtomicInteger没有被其他线程修改,将AtomicInteger的当前数值更新成next的值

    3.3 不等于意味着已经被其他线程修改过,compareAndSet方法会返回false,程序会进入for循环重新进行compareAndSet操作

AtomicBoolean是先把Boolean转换成Integer,再使用compareAndSet进行CAS。所以原子更新char,float,double变量也可以用类似的思路来实现。

注:

1.JDK1.8之后,getAndIncrement实现方式有所调整。使用unsafe封装好的getAndAddInt。

public final int getAndIncrement() {return unsafe.getAndAddInt(this, valueOffset, 1);}

public final int getAndDecrement() {return unsafe.getAndAddInt(this, valueOffset, -1);}

public final int getAndAdd(int delta) {
    return unsafe.getAndAddInt(this, valueOffset, delta);
}

public final int incrementAndGet() {return unsafe.getAndAddInt(this, valueOffset, 1) + 1;}

public final int getAndSet(int newValue) {
    return unsafe.getAndSetInt(this, valueOffset, newValue);
}

public final void lazySet(int newValue) {
    unsafe.putOrderedInt(this, valueOffset, newValue);
}

2.单个方法(如addAndGet)是原子的,但是多个方法(addAndGet)在一个方法内是非原子性的,需要加synchronized进行修饰,保证整体原子性。

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public class AtomicUse {

	private static AtomicInteger count = new AtomicInteger(0);
	
	/**synchronized*/
	public synchronized int multiAdd(){
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			count.addAndGet(1);
			count.addAndGet(2);
			count.addAndGet(3);
			count.addAndGet(4); //+10
			return count.get();
	}
	
	
	public static void main(String[] args) {
		
		final AtomicUse au = new AtomicUse();

		List<Thread> ts = new ArrayList<Thread>();
		for (int i = 0; i < 100; i++) {
			ts.add(new Thread(new Runnable() {
				@Override
				public void run() {
					System.out.println(au.multiAdd());
				}
			}));
		}

		for(Thread t : ts){
			t.start();
		}
	}
}

执行结果:

不加synchronized(结果不唯一)

50
50
50
50
50
60
70
90
110
90
100
120
130
140
150
170
180
160
190
230
220
210
200
247
306
320
290
290
261
270
254
310
336
370
360
350
340
386
430
400
460
450
440
420
390
530
410
540
560
590
600
610
620
550
643
690
520
510
480
500
730
490
480
720
710
700
680
666
670
780
656
830
630
580
840
570
870
890
880
860
850
960
810
790
820
800
760
770
750
740
1000
990
980
970
950
900
940
921
930
910

加synchronized

10
20
30
40
50
60
70
80
90
100
110
120
130
140
150
160
170
180
190
200
210
220
230
240
250
260
270
280
290
300
310
320
330
340
350
360
370
380
390
400
410
420
430
440
450
460
470
480
490
500
510
520
530
540
550
560
570
580
590
600
610
620
630
640
650
660
670
680
690
700
710
720
730
740
750
760
770
780
790
800
810
820
830
840
850
860
870
880
890
900
910
920
930
940
950
960
970
980
990
1000

原子更新数组

通过原子的方式更新数组里的某个元素,Atomic包提供了以下的3个类:
(1)AtomicIntegerArray: 原子更新整型数组里的元素。
(2)AtomicLongArray: 原子更新长整型数组里的元素。
(3)AtomicReferenceArray: 原子更新引用类型数组里的元素。
这三个类的最常用的方法是如下两个方法:
(1)get(int index):获取索引为index的元素值。
(2)compareAndSet(int i,E expect,E update): 如果当前值等于预期值,则以原子方式将数组位置i的元素设置为update值。

原子更新引用类型

Atomic包提供了以下三个类:
(1)AtomicReference: 原子更新引用类型。
(2)AtomicReferenceFieldUpdater: 原子更新引用类型的字段。
(3)AtomicMarkableReferce: 原子更新带有标记位的引用类型。

原子更新字段类

Atomic包提供了3个类进行原子字段更新:
(1)AtomicIntegerFieldUpdater: 原子更新整型的字段的更新器。
(2)AtomicLongFieldUpdater: 原子更新长整型字段的更新器。
(3)AtomicStampedFieldUpdater: 原子更新带有版本号的引用类型。该类将整数值与引用关联起来,可用于原子的更新数据和数据的版本号,可以解决使用CAS进行原子更新时可能出现的ABA问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值