자바에서
Stack
은 왜 효율적이지 않을까?
호기심에서 호기심을 해결하는 과정에서의 공부를 정리해보고자 합니다.
일상적으로 가장 많이 쓰는 List
와 코드를 비교해보자
Stack
의 코드
List
의 코드
두 코드를 비교하면 **Stack**
에만 synchronized
가 선언이 되어있다.
동기화 선언이 효율을 떨어뜨리게 만드는걸까?
먼저 동기화에 대해 짚고 넘어가자
자바에서
synchronized
키워드는
특정 메서드나 블록이 한번에 하나의 스레드만 실행될 수 있도록 보장해준다.
-> 주로 공유 자원에 대한 동시 접근을 제어하여 데이터의 일관성 유지에 사용된다.
synchronized
키워드를 사용하면 해당 메소드나 블록의 모니터를 획득한다.예제로 보면
public static class Synchronized {
private int counter = 0;
public synchronized void increment() {
counter++;
}
public synchronized int getCounter() {
return counter;
}
}
public static class UnSynchronized {
private int counter = 0;
public void increment() {
counter++;
}
public int getCounter() {
return counter;
}
}
선언된 메소드를 만들고
@Test
@DisplayName("동기화 선언된 메소드 동시 접근")
public void testSynchronized() {
Synchronized example = new Synchronized();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
assertThat(example.getCounter()).isEqualTo(2000);
}
위의 두개의 synchronized된 increment() 메소드
를 동시에 실행하는 테스트 코드를 실행하면
2000의 결과가 옳은 것을 확인할 수 있고,
public static class UnSynchronized {
private int counter = 0;
public void increment() {
counter++;
}
public int getCounter() {
return counter;
}
}
동기화되지 않은 메소드를 선언해주고
@Test
@DisplayName("동기화 선언 없는 메소드 동시 접근")
public void testUnSynchronized() {
UnSynchronized example = new UnSynchronized();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
assertThat(example.getCounter()).isNotEqualTo(2000);
}
위의 두개의 synchronized 선언 안 된 increment() 메소드
를 동시에 실행하는 테스트 코드를 실행하면
2000이 아닌 결과가 나온 것을 확인할 수 있다.
위에서 보듯이 동기화는 데이터 일관성과 경쟁 상태 방지와 같은 상황에서 중요하다. 예를 들어 돈과 관련된 입출금, 이전에 공부했었던 로그 그리고 채팅 메시지 처리에도 자주 사용된다고 한다.
최근에 본 글에서 최근의 성능이 좋아서 성능보다는 유지 보수에 용이하게 코드를 작성하는 것을 더 중요시 여긴다는 글을 본 적이 있다.
성능이 좋아 속도의 별 차이가 없다보면 Synchronized를 사용하지 않는 List
보다는 오히려 사용하는 Vector
를 주로 써야되는 것이 아닐까?
Vector
가 더 안전하지만 단순한 get()
기능을 쓴다고 볼 때 모든 메소드가 동기화로 lock이 걸려 오버헤드 발생할 수 있음Vector
보다 List
가 편리Concurrent
컬렉션을 사용Vector
보다 더 나은 성능(관련된 부분만 Lock을 걸기 때문)과 동시성 제공자바에서 Vector와 Stack 컬렉션이 쓰이지 않는 이유
[Java] Synchronized Collection vs Concurrent Collection