[자바] 동시 멀티 스레딩 동작 클래스 12 개 원자

시작 JDK1.5에서 자바가 제공하는 java.util.concurrent.atomic패키지, 패키지 형 원자 작업이 제공하는 사용하기 간단하고 효율적인 성능 변수 스레드 안전 갱신합니다 (CAS 작업, 아니 잠금을 사용) 방식.

`Java.util.concurrent.atomic` 패키지 클래스 .PNG

네 종류의 클래스로 분류 될 수있는 변수의 종류, 원자 패킷 12 개 원자 조작에 따라
① 원자 업데이트 기본 유형 : AtomicBoolean、AtomicInteger、AtomicLong
② 원자 업데이트 어레이 : AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
③ 원자 업데이트 참조 : AtomicReference、AtomicReferenceFiledUpdater、AtomicMarkableReference
④ 원자 업데이트 필드 (특성) : AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicStampedReference
그들이 안전하지 않은 사용 래퍼 클래스의 구현입니다.


원자 갱신 기본 유형 클래스

원자의 기본 유형을 업데이트 사용, 원자 패키지는 다음의 세 가지 범주 제공 :
AtomicBoolean
AtomicInteger
AtomicLong
다음과 같이 제공 거의 정확히 같은 방식의 세 가지 클래스 AtomicInteger를 설명하기 위해 예를 들어, AtomicInteger종래의 방법은 다음과 같다 :

int addAndGet(int delta) 以原子方式将AtomicInteger的value设置为:delta + 原value,返回更新后的值(即delta + 原value) boolean compareAndSet(int expect, int update) 以原子的方式,如果AtomicInteger的当前值是expect,则将AtomicInteger的值设置为update int getAndIncrement() 以原子的方式将AtomicInteger的当前值加1,注意:返回的是加1前的值 void lazySet(int newValue) 最终将AtomicInteger设置为newValue(使用lazySet设置值后,其他线程可能在之后的一段时间内还是可以读到旧的值) int getAndSet(int newValue) 以原子的方式将AtomicInteger设置为newValue 

예를 들어의 기본적인 방법을 사용합니다 :

public void test(){ Executor executor = Executors.newFixedThreadPool(3); AtomicInteger atomicInteger = new AtomicInteger(0); for(int i = 0; i < 10; i++){ executor.execute(()->{ System.out.println("atomicInteger的当前值:" + atomicInteger.addAndGet(1)); }); } } //输出如下(输出顺序可能不同,但结果一定是正确的) atomicInteger的当前值:1 atomicInteger的当前值:2 atomicInteger的当前值:4 atomicInteger的当前值:5 atomicInteger的当前值:3 atomicInteger的当前值:7 atomicInteger的当前值:6 atomicInteger的当前值:9 atomicInteger的当前值:8 atomicInteger的当前值:10 

내부 동작 원리는 원자에 의해 실현된다 UnSafe클래스 CAS운영. //의 TODO 콘크리트 실현
다른 Java기본 유형이 유사한 아이디어를 사용하여 달성 될 수있다.


업데이트 원자의 배열

: 원자의 요소에 의해 어레이를 업데이트 원자 패키지는 다음의 세 가지 범주 제공
AtomicIntegerArray: 원자 업데이트 정수 배열 요소
AtomicLongArray: 요금 원자 긴 정수 배열 요소
AtomicReferenceArray: 레퍼런스 어레이 원자 종류를 업데이트 요소

以AtomicIntegerArray예를 들어, 다음과 같이 주로 정수의 원자 적으로 갱신 배열 요소를 제공하는 주요 방법이있다 :

int addAndGet(int i, int delta) 以原子的方式将数组中i位置处的元素值加上delta,返回:i位置处的元素的旧值+ delta boolean compareAndSet(int i, int expect, int update) 如果当前值等于预期值(数组i位置处的元素),则以原子的方式将数组i位置处的元素值设置为update 

사용 예 :

public void testAtomicIntegerArray() { int[] originArray = new int[]{1, 2, 3}; AtomicIntegerArray array = new AtomicIntegerArray(originArray); array.getAndSet(0, 8); System.out.println(array.get(0)); System.out.println(originArray[0]); } //输出结果: 8 1 ----注意这里,构造方法中是将原数组复制了一份,所以对AtomicIntegerArray的操作,不会影响原数组 

원자 업데이트 참조 유형

변수 복수의 원자를 업데이트하기 위해이 기준 타입 원자를 업데이트 할 필요가, 원자 세 카테고리 제공
AtomicReference: 참조 형 원자 업데이트
AtomicReferenceFiledUpdater원자 업데이트 타입 필드에서 기준 :
AtomicMarkableReference: 참조 형 원자 표시된 위치 업데이트

AtomicReference예를 들어 다음과 같은 코드를 설명합니다 :

class AtomicReferenceExample{

    private  AtomicReference<User> userAtomicReference = new AtomicReference<>(); @Test public void test(){ User originUser = new User(18, "小岳"); userAtomicReference.set(originUser); User updateUser = new User(28, "老岳"); userAtomicReference.compareAndSet(originUser, updateUser); System.out.println(userAtomicReference.get().getName() + ":" + userAtomicReference.get().getAge()); } class User{ private String name; private int age; public User(int age, String name){ this.name = name; this.age = age; } public int getAge() { return age; } public String getName() { return name; } } } //输出结果如下 老岳:28 

원자 업데이트 필드 클래스

당신은 필드에 원자의 클래스를 업데이트해야하는 경우가 원자 갱신 필드 클래스를 사용하는 것이 필요하다, 원자 패키지는 다음과 같은 세 가지 범주 원자 필드 업데이트를 제공합니다.
AtomicIntegerFieldUpdater: 정수 원자 업데이트 필드
AtomicLongFieldUpdater: 긴 정수 원자 업데이트 필드
AtomicStampedReference: 기준 유형 원자 업데이트 버전 번호 ( 문제 CAS 동작 ABA를 해결할 수 )

정적 메소드를 사용해야 업데이트 필드 클래스를 사용하여 newUpdater(Class<U> tclass, String fieldName)업데이트 프로그램을 작성하는 (동시에 지정된 클래스로 업데이트하고 필드 이름의 클래스를 갱신 함), 및 필드를해야 public volatile변성 .

AtomicIntegerFieldUpdater예를 들어 다음과 같은 코드를 설명합니다 :

class AtomicIntegerFieldUpdaterExample{

    private AtomicIntegerFieldUpdater<User> fieldUpdater = AtomicIntegerFieldUpdater.newUpdater(User.class, "age"); @Test public void test(){ User user = new User(18, "小岳"); fieldUpdater.addAndGet(user, 10); System.out.println("user现在的年龄:" + fieldUpdater.get(user)); } class User{ private String name; public volatile int age; public User(int age, String name){ this.name = name; this.age = age; } public int getAge() { return age; } public String getName() { return name; } } } //输出结果如下 user现在的年龄:28 

CAS 사이클을 이해

잠금 루프와 CAS : 자바는 두 가지 방법으로 원자 연산에 의해 구현 될 수있다.
원자 조작 예를 사용하여 자바로 구현 CAS주기 :

//原子操作类AtomicInteger的incrementAndGet实现(最新源码已非如此,但思想是一致的)
public final int incrementAndGet() { for (;;) {//一直循环 int current = get();//取出AtomicInteger当前的内存值 int next = current + 1;//要设置的新值 if (compareAndSet(current, next)){//用CAS操作更新AtomicInteger return next; } } } 

boolean compareAndSet(int current, int newValue)아톰 먼저 확인하는 방법이며, AtomicInteger전류 값은 (메모리로부터 판독, 즉 메모리 CAS 동작 값)은 동일한 current것이 동일한 경우, 다음 (즉, 기대 값 연산 CAS) AtomicInteger다른 값은 아니다 그것이 될 것이다 수정 된 스레드 AtomicInteger값 세트 newValue(즉, 새로운 값 CAS 동작 수정할 수)를 반환 true같지 않음을 나타내는 경우는 AtomicInteger다른 쓰레드에 의해 변형 된 값을 반환 한 다음 fasle.

CAS의 자성 작업을 세 가지 질문

①ABA 문제 .
CAS에이 값에 따라 동작시의 값을 확인해야하기 때문에 업데이트되는 변경되지 않은 경우 변경되지 않지만 값이 경우는, B되었다, 그는 A는, 당신은 발견 할 것이다 그 CAS 검사를 사용하는 경우 그 값은 변경하지만, 실제로는 변경되지 않았습니다.
솔루션 ABA 문제는 버전 번호를 사용하는 것입니다. 버전 번호는 각각의 변수는 버전 번호를 플러스 한 후 A-B-A는 1A-2B-3A 될 때 갱신되는 변수의 앞에 추가된다.
JDK의 원자 Java1.5 패키지의 시작부터 ABA 문제를 해결하기 위해 클래스 AtomicStampedReference를 제공합니다. 이 클래스의 작업에있어서의 compareAndSet 현재 참조 예상 기준 같으며 모든 동일한 원자 기준 값 및 상기 플래그가 지정된 갱신 값으로 설정된 경우 현재 마크가 예상 플래그와 같은지 검사한다.

② 긴 사이클 시간은 큰 지출 .
시간이 성공적으로 스핀 CAS가 아닌 경우는 매우 큰 CPU의 실행 비용을 가져올 것이다.

③ 원자 조작은 공유 변수를 보장 할 수 있습니다 .
공유 변수에 대한 작업을 수행 할 때, 우리는 원자 작동을 보장하기 위해 CAS 사이클 접근 방식을 사용하지만, 사이클 CAS를 동작하는 다수의 공유 변수가 원자 작업을 보장 할 수없는 경우,이 시간을 당신이 잠금을 사용할 수 있습니다, 또는 수 까다로운 방법은, 동작하는 공유 변수에 복수의 공유 변수를 병합한다. 예를 들어 두 개의 공유 변수가있다 I = 2, J = A, IJ = 2A로 병합하고, CAS ij에 동작하도록. 객체의 참조 원자를 보장하기 위해 제공 시작 Java1.5 JDK 클래스의 AtomicReference에서는 CAS 조작 변수와, 상기 복수의 대상물을 나올 수 행한다.


참고

모든 "자바 동시 프로그래밍의 예술"의 내용과는 말했다 책의 저자 토크 동시 (E) - 원자 연산의 원리 .


저자 : maxwellyue
링크 : HTTPS : //www.jianshu.com/p/712681f5aecd
출처 : 제인 책
저자가 보유 제인 책의 저작권은, 어떤 형태로도 복제되어, 승인을 얻기 위해 작성자에게 문의하고 소스를 표시하시기 바랍니다.

추천

출처www.cnblogs.com/xiaoshen666/p/11258541.html