synchronized , static synchronized, 재진입성

Dayeon myeong·2022년 3월 4일
0

면접

목록 보기
7/35

synchronized

synchronized는 여러 스레드들이 동시 접근할 수 있는 임계 영역에 대해 모니터락을 걸어 동기화를 할 수 있다.

모니터락을 사용하여 락을 가진 객체를 지정할 수 있다. Synchronized 메소드나
Synchronized블록을 통해 락을 확보하며, 해당 블록을 벗어날 때 락이 해제된다.
하지만 synchornized는 아예 락을 걸어버리는 것이기 때문에 성능에 영향을 줄 수 있다.
어떤 메서드에 synchronized를 걸어버리면 해당 메서드는 한번에 한 스레드만 실행하기 때문에 동시 처리가 불가하고,서블릿 프레임워크같이 요청별로 스레드를 생성해서 동시에 여러 요청을 처리해야할 경우 속도가 느려진다. 다른 클라이언트 요청은 현재 요청이 완료할 때까지 마냥 기다려야 한다.

따라서 synchronized 블록의 크기를 적정하게 유지하여야 한다.

synchronized 를 메소드에 선언하는 것과, 특정 객체에 선언하는 것은 어떤 차이가 있습니까?

synchronized 메소드는 synchronized(this) {} 블럭과 같다고 생각하면 되며, 현재 인스턴스에 대해서 락을 획득한다.
만약 2개 이상의 인스턴스가 있다면 각각의 인스턴스에 대해 모니터락이 걸린 것이므로, 두 개의 인스턴스가 각각의 method를 실행하는 것이 가능하다.
해당 메서드 락을 획득하고 나서 메서드 블록을 벗어나면 락을 반납한다.

//둘 클래스는 같은 거임 
public class SynchronizedTest {

	public synchronized void a() {... }

	
	public synchronized void b() {... }

}

public class SynchronizedTest {

	public static void a() {
		synchronized(this) {... }
	}

	
	public static void b() {
		synchronized(this) {... }
	}

}

synchronized를 특정 객체에 선언하는 것은 synchronized 블록을 사용하는 것이다. synchronized 메서드는 현재 객체 자체에 락을 거는 것이지만, synchronized 블록은 특정 객체에만 락을 걸어서 최소한의 필요한 영역에만 락을 걸 수 있다. lock 블록의 범위를 줄인 것이기 때문에 동시성을 향상시킬 수 있다.

static synchronized

synchrnozied 메서드는 각각의 인스턴스에 락을 거는 반면,static synchronized는 해당 클래스 자체에 락을 획득한다.
클래스를 사용할 때 한번에 단 하나의 스레드만 사용하게 되는 것이다. Static synchronized에서 락을 건 객체는 해당 클래스가 최초 로딩될 때 생성되는 클래스 타입 정보를 담고 있는 Class 클래스 타입의 인스턴스이다.
이 Class라는 클래스 타입의 인스턴스에 대한 락을 획득한다고 보면 된다.

//둘 클래스는 같은 거임
public class StaticSynchronizedTest {

	public static synchronized void a() {... }

	
	public static synchronized void b() {... }

}

public class StaticSynchronizedTest {

	public static void a() {
		synchronized(StaticSynchronizedTest.class) {... }
	}

	
	public static void b() {
		synchronized(StaticSynchronizedTest.class) {... }
	}

}

재진입성

synchronized는 재진입 reentrant 가 가능하여 특정 스레드가 자기가 이미 획득한 락을 다시 확보할 수 있다. 원래는 스레드가 다른 스레드가 가진 락을 요청하면 해당 스레드는 대기 상태에 들어간다. 따라서 특정 스레드가 이미 획득되어있는 락을 획득하려 하면 대기상태에 빠지고 데드락에 걸리게 된다. 하지만 재진입덕분에 동일 락에 대해 데드락을 피할 수 있다.

JVM은 누가 락을 획득했는지, 확보 횟수는 얼마인지를 기록해둔다. 만약 같은 스레드가 락을 다시 얻으면 횟수를 증가시키고, 소유한 스레드가 synchronized블록 밖으로 나가면 횟수를 감소시킨다. 이렇게 횟수가 0이되면 해당 락은 해제된다.

public class Widget {
	public synchronized void doSomething() {
    	...
    }
}

public class LoggindWidget extends Widget {
	public synchronized void doSomething() {
    	System.out.println(toString() + ": calling doSomething");
        super.doSoemthing();
    }
}



Widget lw = new LoggindWidget();
lw.doSomething(); 

lw인스턴스에 synchronized 락을 걸면 synchronized(this) 에 의해서 widget, loggindwidget 두 클래스에 대한 인스턴스에 락이 걸린것이다.

처음 dosomething에서 이미 락이 걸려있는데 또 다시 이미 획득한 동일 락을 확보하여 재진입을 가능하게 한다.

profile
부족함을 당당히 마주하는 용기

0개의 댓글