Java의 AtomicInteger
오늘은 Java의 AtomicInteger
에 대해 살펴보겠습니다. 원자성 작업은 다른 작업의 간섭 없이 단일 작업 단위에서 수행됩니다. 데이터 불일치를 피하기 위해 다중 스레드 환경에서 원자적 작업이 필요합니다.
AtomicInteger
package com.journaldev.concurrency;
public class JavaAtomic {
public static void main(String[] args) throws InterruptedException {
ProcessingThread pt = new ProcessingThread();
Thread t1 = new Thread(pt, "t1");
t1.start();
Thread t2 = new Thread(pt, "t2");
t2.start();
t1.join();
t2.join();
System.out.println("Processing count=" + pt.getCount());
}
}
class ProcessingThread implements Runnable {
private int count;
@Override
public void run() {
for (int i = 1; i < 5; i++) {
processSomething(i);
count++;
}
}
public int getCount() {
return this.count;
}
private void processSomething(int i) {
// processing some job
try {
Thread.sleep(i * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
위의 프로그램을 실행하면 count
값이 5,6,7,8 사이에서 변하는 것을 알 수 있습니다. 그 이유는 count++가 원자 연산이 아니기 때문입니다. 따라서 한 스레드가 값을 읽고 1씩 증가할 때까지 다른 스레드는 잘못된 결과로 이어지는 이전 값을 읽었습니다. 이 문제를 해결하려면 카운트에 대한 증가 연산이 원자적임을 확인해야 합니다. 동기화를 사용하여 이를 수행할 수 있지만 Java 5 java.util.concurrent.atomic
은 int 및 long에 대한 래퍼 클래스를 제공합니다. 동기화를 사용하지 않고 이 원자적 작업을 달성하는 데 사용할 수 있습니다.
자바 AtomicInteger 예제
다음은 AtomicInteger
메서드 incrementAndGet()
가 현재 값을 원자적으로 1씩 증가시키기 때문에 카운트 값을 항상 8로 출력하는 업데이트된 프로그램입니다.
package com.journaldev.concurrency;
import java.util.concurrent.atomic.AtomicInteger;
public class JavaAtomic {
public static void main(String[] args) throws InterruptedException {
ProcessingThread pt = new ProcessingThread();
Thread t1 = new Thread(pt, "t1");
t1.start();
Thread t2 = new Thread(pt, "t2");
t2.start();
t1.join();
t2.join();
System.out.println("Processing count=" + pt.getCount());
}
}
class ProcessingThread implements Runnable {
private AtomicInteger count = new AtomicInteger();
@Override
public void run() {
for (int i = 1; i < 5; i++) {
processSomething(i);
count.incrementAndGet();
}
}
public int getCount() {
return this.count.get();
}
private void processSomething(int i) {
// processing some job
try {
Thread.sleep(i * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
원자적 작업에 동시성 클래스를 사용하면 동기화에 대해 걱정할 필요가 없다는 이점이 있습니다. 이렇게 하면 코드 가독성이 향상되고 오류 가능성이 줄어듭니다. 또한 원자적 작업 동시성 클래스는 리소스 잠금과 관련된 동기화보다 더 효율적이라고 가정합니다.