AtomicInteger 사용

자바 에 서 는 i++ + i 가 원자 조작 이 아니 므 로 다 중 스 레 드 환경 에서 synchronized 키 워드 를 사용 해 야 합 니 다.JDK 1.5 의 java. util. concurrent. atomic 패 키 지 는 원자 조작 클래스 를 제공 하고 Unsafe 클래스 를 네 이 티 브 로 조정 하 는 방법 을 통 해 이 루어 집 니 다.
  여 기 는 AtomicInteger 를 예 로 들 면:
내부 저장 소
전체 값 을 지 켰 습 니 다. 초기 값 은 0 입 니 다.다 중 스 레 드 작업 을 고려 하여 volatile 을 사용 하여 가시 성 을 확보 합 니 다.

private volatile int value;

단독 할당 작업
구조 함수 설정:

public AtomicInteger(int initialValue) {
	value = initialValue;
}

Setter:

public final void set(int newValue) {
	value = newValue;
}

지연 할당:

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

가 져 오기 및 할당 복합 작업:
Getter:

public final int get() {
	return value;
}

원래 값 가 져 오기 및 새 값 설정:

public final int getAndSet(int newValue) {
	for (;;) {
		int current = get();
		if (compareAndSet(current, newValue))
			return current;
	}
}

원래 값 가 져 오기 및 자동 증가:

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

원래 값 가 져 오기 및 자동 감소:

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

원래 값 가 져 오기 및 지정 값 추가:
dela 는 마이너스 로 getAndSubtract 기능 을 실현 할 수 있 습 니 다.

public final int getAndAdd(int delta) {
	for (;;) {
		int current = get();
		int next = current + delta;
		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 int decrementAndGet() {
	for (;;) {
		int current = get();
		int next = current - 1;
		if (compareAndSet(current, next))
			return next;
	}
}

지정 한 값 을 추가 하고 새 값 가 져 오기:
이와 같이 델 타 는 마이너스 로 subtractAndGet 기능 을 실현 할 수 있다

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

이 를 통 해 알 수 있 듯 이 위의 방법 은 비교적 유사 하 다. copare Andset 방법 을 순환 적 으로 호출 하고 성공 하면 되 돌아 오 는 것 이다.
compreAndSet 방법 보기:

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

또한, weakCompare AndSet 방법 도 제공 하 였 으 며, 호출 된 unsafe 방법 은 위 와 같 습 니 다.

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

성능 테스트
1. synchronized 와 비교 하여 단일 스 레 드 는 1000 w 회 자체 증가 작업 을 수행 합 니 다.

public class AtomicIntegerSynchTest {

	private int value;
	
	public AtomicIntegerSynchTest(int value) {
		this.value = value;
	}
	
	public synchronized int increase() {
		return value++;
	}
	
	public static void main(String[] args) {
		long start = System.currentTimeMillis();
		
		AtomicIntegerSynchTest test = new AtomicIntegerSynchTest(0);
		for (int i = 0; i < 10000000; i++) {
			test.increase();
		}
		long end = System.currentTimeMillis();
		System.out.println("Synch elapsed: " + (end - start) + "ms");
		
		long start2 = System.currentTimeMillis();
		AtomicInteger atomicInt = new AtomicInteger(0);
		for (int i = 0; i < 10000000; i++) {
			atomicInt.incrementAndGet();
		}
		long end2 = System.currentTimeMillis();
		System.out.println("Atomic elapsed: " + (end2 - start2) + "ms");
	}
}

출력:
Synch elapsed: 383ms
Atomic elapsed: 208 ms (단일 스 레 드 환경 에서 Atomic Integer 는 동기 화 성능 보다 약간 좋 습 니 다)
2. 다 중 스 레 드 여러 번 조작:
여 기 는 100 개의 스 레 드 를 사용 하여 스 레 드 마다 10w 번 의 자체 증가 작업 을 수행 합 니 다. 100 개의 스 레 드 를 동시에 실행 하 는 데 걸 리 는 시간 을 통계 하기 위해 Count Downlatch 를 사용 하여 조 화 를 이 룹 니 다.

public class AtomicIntegerMultiThreadTest {

	private /*volatile*/ int value;

	public AtomicIntegerMultiThreadTest(int value) {
		this.value = value;
	}

	public synchronized int increase() {
		return value++;
	}
	
	public int unSyncIncrease() {
		return value++;
	}
	
	public int get() {
		return value;
	}

	public static void main(String[] args) throws InterruptedException {
		long start = System.currentTimeMillis();

		final CountDownLatch latch = new CountDownLatch(100);

		final AtomicIntegerMultiThreadTest test = new AtomicIntegerMultiThreadTest(0);
		for (int i = 0; i < 100; i++) {
			new Thread(new Runnable() {

				@Override
				public void run() {
					for (int i = 0; i < 100000; i++) {
						test.increase();
						//test.unSyncIncrease();
					}

					latch.countDown();
				}
			}).start();
		}

		latch.await();
		long end = System.currentTimeMillis();
		System.out.println("Synch elapsed: " + (end - start) + "ms, value=" + test.get());

		long start2 = System.currentTimeMillis();
		final CountDownLatch latch2 = new CountDownLatch(100);
		final AtomicInteger atomicInt = new AtomicInteger(0);
		for (int i = 0; i < 100; i++) {
			new Thread(new Runnable() {

				@Override
				public void run() {
					for (int i = 0; i < 100000; i++) {
						atomicInt.incrementAndGet();
					}
					
					latch2.countDown();
				}
			}).start();
		}

		latch2.await();
		long end2 = System.currentTimeMillis();
		System.out.println("Atomic elapsed: " + (end2 - start2) + "ms, value=" + atomicInt.get());
	}
}

출력:
Synch elapsed: 1921ms, value=10000000
Atomic elapsed: 353 ms, value = 10000000 (AtomicInteger 의 성능 은 synchronized 의 5 배가 넘 습 니 다)
value 에 volatile 수식 자 를 추가 할 때:
Synch elapsed: 2268 ms, value = 10000000 (volatile 코드 정렬 금지, 어느 정도 성능 저하)
Atomic elapsed: 337ms, value=10000000
동기 화 되 지 않 은 자동 증가 방법 unSyncIncrease 를 호출 할 때:
Synch elapsed: 216 ms, value = 5852266 (비원 자 조작 이 동기 화 되 지 않 아 결과 오류 발생)
Atomic elapsed: 349ms, value=10000000

좋은 웹페이지 즐겨찾기