오늘은 Java에서 AtomicInteger
을 살펴볼 것입니다. 원자 연산은 다른 작업의 간섭 없이 단일 작업 단위에서 수행됩니다. 원자 연산은 데이터 불일치를 피하기 위해 다중 스레드 환경에서 필수적입니다.
AtomicInteger
각 스레드가 공유
count
변수를 4번 증가시키는 간단한 다중 스레드 프로그램을 만들어 보겠습니다. 따라서 스레드가 두 개 있다면, 그들이 작업을 마친 후 count
값은 8이어야 합니다. JavaAtomic.java
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) {
// 작업 처리
try {
Thread.sleep(i * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
위의 프로그램을 실행하면 count
값이 5, 6, 7, 8 사이로 변하는 것을 알 수 있습니다. 그 이유는 count++가 원자적 연산이 아니기 때문입니다. 따라서 한 스레드가 그 값을 읽고 하나를 증가시킬 때까지 다른 스레드가 이전 값을 읽어 오류가 발생합니다. 이 문제를 해결하기 위해 count의 증가 작업이 원자적임을 확인해야 합니다. 이를 위해 동기화를 사용할 수 있지만 Java 5 java.util.concurrent.atomic
은 동기화 사용 없이 이러한 원자적 작업을 수행할 수 있는 int와 long의 래퍼 클래스를 제공합니다.
Java AtomicInteger 예제
여기에는 항상 카운트 값이 8로 출력되는 업데이트된 프로그램이 있습니다. 왜냐하면 AtomicInteger
메서드 incrementAndGet()
가 현재 값에 1을 원자적으로 증가시키기 때문입니다.
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) {
// 작업 처리
try {
Thread.sleep(i * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
원자 연산에 대한 동시성 클래스 사용의 장점은 동기화에 대해 걱정할 필요가 없다는 것입니다. 이는 코드 가독성을 향상시키고 오류 가능성을 줄입니다. 또한, 원자 연산 동시성 클래스가 리소스를 잠그는 동기화보다 더 효율적이라고 가정됩니다.
Source:
https://www.digitalocean.com/community/tutorials/atomicinteger-java