(Java멀티쓰레드 디자인패턴) Single Threaded Execution

* SharedResource(공유자원) 역할
-> SharedResource 역할을 하는 클래스는 복수의 쓰레드에서 액세스한다. SharedResource는 몇개의 메소드를 가지는데 대체로 2종류로 분류된다.

  • safeMethod : 복수의 쓰레드에서 호출해도 아무런 문제가 없는 메소드
  • unsafeMethod : 복수의 쓰레드가 호출하면 안되기 때문에 가드(Guard)가 필요한 메소드

자바에서는 unsafeMethod를 synchronized 로 함으로써 가드한다.
싱글쓰레드로 동작시켜야 하는 범위를 크리티컬 섹션이라한다.



-------------------------------------------------------------------------------------------------

<적용가능성>

  • 멀티쓰레드
  • 복수의 쓰레드가 액세스 할 때 : 멀티쓰레드 프로그램이더라도 모든 쓰레드가 독립적으로 동작하고 있다면 SingleThreaded Execution 패턴을 사용할 필요가 없다.
  • 상태가 변화할 가능성이 있을 때 : 인스턴스가 만들어진 후에 상태가 변화할 가능성이 전혀 없다면 Single Threaded Execution 을 사용할 필요가 없다. 이것이 Immutable패턴이다. 
  • 안전성을 확보할 필요가 없을 때 

* Single Threaded Execution의 문제점은 데드락을 일으킬 수 있다는 것이다


<크리티컬 섹션의 크기와 수행능력>
  1. 락을 취득하는데 시간이 걸리기 때문
->synchronized메소드에 들어갈 때에는 객체의 락을 취하게 되는데 이 처리에는 시간이 걸리게 된다. 
    2. 쓰레드의 충돌로 대기하게 되기 때문
-> 쓰레드 A가 크리티컬 섹션에서 처리를 실행하고 있는 동안 크리티컬 섹션에 들어가려고 했던 쓰레드 B는 블록한다. 이러한 상황을 쓰레드의 충돌(Conflict)라 한다.
충돌이 일어나면 쓰레드가 대기하는 시간만큼 전체적으로 수행능력이 떨어진다.


  • Hashtable uses single lock for whole data. ConcurrentHashMap uses multiple locks on Segment level (16 by default) instead of object level i.e. whole Map.


* synchronized  vs lock(), unlock()

-> synchronized 는 예외처리나 return상황에서도 확실하게 락을 해제해준다. 반면에 후자는 락이 해제 되지 않을 수 있다.
그러므로
try{
.....
}
finally{
   unlock();
}
해주어야 한다.

* 어떤 단위로 지켜야 하는가?

1. public synchronized void pass(String name, String address){
this.counter++;
this.name = name;
this.address = address;
check();
}

2. public synchronized void setName(String name){
     this.name = name;
}
  public synchronized void setAddress(String Address){
   this.address = address;
 }

-->1번과 2번의 차이점은 2번은 name,과 address 를 만들면 쓰레드가 각각의 필드에 따로따로 대입할 수 있게 된다는 것입니다. 


* 어떤 락을 사용해서 지키고 있는가?

->synchronized 한 인스턴스를 실행하는 쓰레드는 this의 락을 취해야 한다. 어떤 인스턴스의 락을 취할 수 있는 것은 딱 한 개의 쓰레드로 한정되어 있습니다. 
한편 인스턴스가 다르면 락도 다릅니다. 
[어떤 락을 사용해서 지키고 있는가?] 가 특히 문제가 되는 것은 synchronized 블록이다. 
synchronized 블록에서는 어떤 인스턴스의 락을 취할지를 명시적으로 지정하기 때문이다. 
예) synchronized(obj){
......
}

이경우는 인스턴스를 obj로 지정하고 있는 것이다.


* 최소단위의 조작

-> 한개의 쓰레드가 synchronized메소드를 실행하는 동안 다른 쓰레드는 실행할 수 없는 것

* long과 Double 은 최소단위로 취급하지 않는다.

->Java언어 사양에서는 최소단위의 조작이 처음부터 정의 되어있습니다. 예를들어, char나 int등은 기본형(primitive)의 대입이나 참조는 최소단위이다. 또 객체 등 참조형의 대입이나 참조도 최소 단위이다. 애초부터 최소단위이므로 synchronized를 붙일 필요가 없습니다. 

예외적으로 long과 double의 대입이나 참조는 최소 단위가 아니다.
long 과 double 의 대입.참조가 최소단위 조작이 아니므로 long이나 double필드를 쓰레드 사이에서 공유할 경우, 그 필드에 대한 조작은 single Threaded Execution 패턴을 사용해 이루어져야 한다.
가장 간단한 방법은 synchronized 메소드 안에서 조작하는 것이다.

다른 방법은 volatile라는 키워드를 붙이면 그 필드의 조작은 최소 단위가 된다.



<계수 세마포어>

계수 세마포어란 [최대 N개의 쓰레드]까지 실행 할 수있도록 설정하는 것.
java.util.concurrent 패키지에서는 계수 세마포어를 나타내는 Semaphore 클래스를 제공한다.





댓글

이 블로그의 인기 게시물

(18장) WebSocekt과 STOMP를 사용하여 메시징하기

(네트워크)폴링방식 vs 롱 폴링방식

(ElasticSearch) 결과에서 순서 정렬