Synchronized Block, Synchronized method



동기화(Synchronized)


- 공유 데이터(나머지 synchronized 된부분) 에 lock을 걸어 작업중이던 쓰레드가 마칠때까지 다른 쓰레드에게 제어권이 넘어가지 않게 보호한다.

- 교착상태에 주의해야 한다.



쓰레드는 같은 프로세스 내 데이터를 공유하기 때문에 일관성에 영향을 끼칠 수 있다. 

만약 공유하는 자원을 처리하던 중 다른 쓰레드가 접근하기라도 한다면 ? 


즉 동기화를 통해, 위와 같은 상황을 방지하고 어느 한 시점에 하나의 쓰레드만 접근하여 자원을 선점하고 프로그래머는 이를 효율적으로 관리할 필요가 있다. 


예를 들어, 작업 중인 문서에 누군가 들어와 편집을 해서 내가 했던 자료가 날라갔다고 가정하면 큰 낭패 일 것이다. 작업중인 문서에 lock을 걸어 다른 사람의 편집권한을 막는 것과 같은 이치라고 생각하면 된다.


ex) Singleton Pattern의 인스턴스를 여러 객체가 접근 할 때, Static으로 정의된 객체를 여러 객체가 접근 할 때, 하나의 객체에 여러 개의 쓰레드가 접근하려고 할 때.. 




 





사용법


(1) 특정 객체 인스턴스에 lock을 걸려고 할 때 - synchronized block

private Worker wokrer = new Worker();


public void work(){

synchronized(worker){


//input


}


}



(2) 메소드에 lock을 걸 때 - synchronized method

public synchronized work(){


//input code

Worker worker = new Worker();

}



특정 인스턴스의 사용을 동기화 할 것이냐?  혹은 메소드 자체를 동기화 할 것이냐?의 구분의 차이로 인식하면 쉬울 것 같다. 

사소하지만 주의깊게 생각해야 할 점이 있다면, (1) 번의 경우 synchronized 된 부분이 임계 영역이라면, (2) 번의 경우 메소드 전체가 임계영역이 된다는 점이다.





Sample Code


class Worker { private Object obj; private int count=0; public Worker() { } public synchronized void writeData(Object obj) { this.obj = obj; count++; } public Object getObj() { return obj; } public void setObj(Object obj) { this.obj = obj; } @Override public synchronized String toString() { return "Worker [obj=" + obj + ", count=" + count + "]"; } } public class Main { public static void main(String[] args) {

//Worker라는 하나의 인스턴스를 공유할 것이다. Worker worker = new Worker(); Thread thread1 = new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub while (true) { try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } worker.writeData("Writer1"); System.out.println("Data Print :"+worker.toString()); } } }); Thread thread2 = new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub while (true) { try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } worker.writeData("Writer2"); System.out.println("Data Print :"+worker.toString()); } } }); thread1.start(); thread2.start(); } }



- WriteData 메소드와 toString 메소드를 동기화함에 따라 순차적인 Count 증가 및 Data를 Write할 수 있었다.





=>결과 출력







위의 방법처럼 synchronized 된 메소드를 구성했다면 , 객체를 synchronized 하여 구성하는 것도 쉽게 할 수 있을 것이다.















+ Recent posts