쓰레드의 문제점
변수 num에 저장되있는 값을 두개의 쓰레드가 증가시키는 상황일때
변수의값이 99일때 쓰레드 1이 변수 num의값 99를참조된 값을 증가된값 100을얻고 변수 num에저장한다.
이어서 쓰레드 2도 변수num의값 100을 참조하여 101을 얻고 연산이완료된 값을 num에 저장한다.
이는 매우 이상적인 상황이다 쓰레드 1이 변수 num에 저장된 값을 증가시키기 전에 쓰레드2로
cpu의 실행이 넘어갈수 있기 때문이다.
쓰레드1이 변수 num에 저장된 값99를 참조하여 증가연산 시킨 값 100을얻고 저장하기 전에
쓰레드 2가 num에 참조를 하게되면 증가하기 전 값인 99를 참조해 증가시킨값 100을 얻는다.
쓰레드1이 증가된값 100을 num에 저장하면 쓰레드 2도 증가된값 100을 저장한다.
증가된 변수에 쓰레드 2가 다시 100을 저장하는 일이 발생한다.
한쓰레드가 연산을 완료 할 때까지 다른 쓰레드가 접근하지 못하도록 하는것이 동기화(Synchronization)이다.
동기화메소드
1 2 3 | public synchronized void increment(){ } | cs |
메소드선언에 synchronized 선언을 해주면 이는 동기화 메소드가 된다.
동기화 메소드는 한 순간에 하나의 쓰레드만 호출이 가능하다.
쓰레드A가 이 메소드를 호출한 상태에서 쓰레드B가 이 메소드를 호출하면
쓰레드B는 쓰레드A가 메소드의 실행을 완료할 때 까지 기다리고 있다가 완료가 되면 실행을하게된다.
단점 - 실행시간이 오래걸린다. 쓰레드의 동기화로 인해 성능이 많이 저하된다.
동기화메소드에 의해서 동기화 되는 영역은 인스턴스 전체이다.
자바의 모든 인스턴스에는 하나의 열쇠가 존재한다. 이열쇠는 lock또는 monitor라한다.
synchronized 로 선언된 메소드에는 자물쇠가 걸리고 호출하려면 열쇠가 필요하다.
열쇠는 하나이기때문에 synchronized선언된 메소드는 동시에 둘 이상이 실행될수 없다.
동기화블록
동기화가 필요한 코드의양은 적은데 synchronized 선언이 돼있어 성능이 감소할때
동기화의 대상을 메소드 전부가 아니라 코드 블록 일부로 제한할 필요가 있다.
1 2 3 4 5 6 7 8 9 10 11 12 | public synchronized int add(int n1, int n2){ synchronized (this) { opCnt++; } return n1+n2; } public synchronized int min(int n1, int n2){ synchronized (this) { opCnt++; } return n1-n2; } | cs |
동기화 블록에서 괄호 사이에 this가 삽입되어있다.
이 위치는 '어디에 있는 열쇠를 가져와 동기화를 하겠냐?' 를 묻는 위치이다.
동기화하지 말아야하는 상황의 메소드를 모두 동기화 메소드로선언하는것은 적절하지 못하다.
자바의 모든인스턴스에는 하나의 열쇠가 있다. 열쇠로 사용하기위해 생성된 인스턴스의 열쇠로
동기화 블럭에 열쇠를 지정하면 과도한 동기화로 인한 성능 저하가 발생하지 않는다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class HaveTwoNum { Object key1 = new Object(); //열쇠 생성 public void addOneNum1(){ synchronized (this) {num1+=1;} //num1에 접근하는 메소드 this 키 기준으로 동기화 } public void addTwoNum1(){ synchronized (this) {num1+=2;} //num1에 접근하는 메소드 this 키 기준으로 동기화 } public void addOneNum2(){ synchronized (key) {num2+=1;} //num2에 접근하는 메소드 key 키 기준으로 동기화 } public void addTwoNum2(){ synchronized (key) {num2+=2;} //num2에 접근하는 메소드 key 키 기준으로 동기화 } } | cs |
this로부터 얻은 열쇠와 열쇠가 더필요할 때 Object인스턴스를 생성해 얻은 열쇠로
동기화가 필요한 부분에 동기화를 한다.
'Java' 카테고리의 다른 글
쓰레드의 특성 (0) | 2017.02.26 |
---|---|
쓰레드 Thread (0) | 2017.02.26 |
Map<K,V> 인터페이스 (0) | 2017.02.26 |
배열 (Array) / forEach (0) | 2017.02.26 |
HashSet<E> / TreeSet<E> (0) | 2017.02.26 |