여러 스레드가 작동하는 환경에서 문제없이 동작하는 것
= 동시성 이슈 해결
조회수라는 변수에 여러 스레드가 접근하여 각 스레드가 조회수의 값을 변경시키고 조회하는 경우
스레드 1, 2가 동시에 count 변수에 접근해서 같은 값을 조회하고, 각 스레드에서 조회수를 1씩 늘리고자 했다. 하지만 조회수가 102가 되지 못했다.
스레드 안전성을 지키는 방법
자바 multi thread 환경에서 동시성 제어를 위한 방법을 알아보자.
대표적인 방법으로 synchronized, volatile, atomic이 있다.
변수를 공유하는 방법
public class SharedObject {
public volatile int count = 0;
}
synchronized block에 한 스레드가 참조하는 동안 다른 스레드는 대기
메서드 lock
class Count {
private int count = 0;
public synchronized int view() {
return count++;
}
}
변수 lock
class Count {
private Integer count = 0;
public int view() {
synchronized (this.count) {
return count++;
}
}
}
synchronized 키워드 없이 명시적으로 ReentrantLock 생성, 사용
public class Application {
public static void main(String[] args) {
Count count = new Count();
for (int i = 0; i < 100; i++) {
Thread thread = new Thread(new CountThread(count));
thread.start();
}
}
}
class Count {
private int count = 0;
private Lock lock = new ReentrantLock();
public int view() {
return count++;
}
public Lock getLock() {
return lock;
}
}
class CountThread implements Runnable {
private final Count count;
public CountThread(Count count) {
this.count = count;
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
count.getLock().lock();
System.out.println(count.view());
count.getLock().unlock();
}
}
}
자바 1.5 버전의 java.util.concurrent 동시성 제어 유틸리티 패키지
원자성을 보장하는 변수. synchronized 키워드 없이 동기화문제를 해결하기 위해 고안된 방식
class Count {
private AtomicInteger count = new AtomicInteger(0);
public int view() {
return count.getAndIncrement();
}
}
public class AtomicInteger extends Number implements java.io.Serializable {
private volatile int value;
public final int incrementAndGet() {
int current;
int next;
do {
current = get();
next = current + 1;
} while (!compareAndSet(current, next));
return next;
}
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
}
한 번 만들면 그 상태가 변하지 않는 객체