[Synchronized 키워드]
Java 언어에서 '동시성'은 필수 요소 이다.
여러 스레드가 공유 리소스에 액세스 할 때, 기타 동기화 관련 문제를 피하기 위해,
한 번에 하나의 스레드만 리소스에 액세스 할 수 있도록 하는 것이 중요하다.
Java에서 이를 가능하게 하는 한 가지 방법은 synchronized 키워드를 사용하는 것이다.
이처럼 공유된 리소스의 '동시성' 문제와 동기화 관련 문제를 방지하는
synchronized 키워드의 대상은 instance method와 static method 가 된다.
이 글에서는 이 synchronized 키워드가 어떻게 동작하는지,
해당 키워드를 instance method와 static method에 적용하면 무엇이 다른지에 대해 알아볼 예정이다.
1. 스레드 생성
static method가 대상일 경우,
소속된 클래스의 인스턴스 생성없이 속해있는 클래스 명 자체로 메서드 실행이 가능하므로
클래스 그 자체를 사용하여 메서드를 실행하는 스레드를 생성한다.
즉, static 메서드의 경우에는 여러 개의 스레드를 통해 동시에 실행이 불가능하다.
instance method가 대상일 경우, 해당 메서드가 속해있는 클래스의 인스턴스를 생성하고
생성된 인스턴스를 통해 메서드를 실행하도록 하여 스레드를 생성한다.
즉, 여러 인스턴스를 생성하면 특정 메서드를 동시에 실행이 가능하다.
2. Synchronized static method
static method를 실행하는 스레드는 해당 클래스 그 자체를 사용하여 메서드를 실행하기 때문에
한번에 하나의 스레드만이 해당 클래스에 속한 synchronized static method중 단 1개만을 실행할 수 있다.
3. Synchronized instance method (non-static method)
synchronized instance method를 실행하는 스레드는
해당 클래스를 객체화한 인스턴스를 사용해 메서드를 실행하기 때문에
다른 인스턴스 객체를 사용하는 스레드를 이용할 경우, 동시에 메서드를 실행할 수 있다.
만약 하나의 스레드가 synchronized instance method에 접근하여 실행 중 일때,
같은 클래스의 인스턴스를 사용한 다른 스레드가 해당 메서드에 접근하려하면,
이미 동작 중인 스레드가 완료될 때 까지 차단된다.
3. 예제
class Example {
static int staticCounter = 0;
int instanceCounter = 0;
public static synchronized void incrementStaticCounter() {
staticCounter++;
System.out.println("Static counter: " + staticCounter);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void incrementInstanceCounter() {
instanceCounter++;
System.out.println("Instance counter: " + instanceCounter);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Example instance1 = new Example();
Example instance2 = new Example();
// Create two threads for static method
Thread t1 = new Thread(() -> Example.incrementStaticCounter());
Thread t2 = new Thread(() -> Example.incrementStaticCounter());
// Create two threads for instance methods
Thread t3 = new Thread(() -> instance1.incrementInstanceCounter());
Thread t4 = new Thread(() -> instance2.incrementInstanceCounter());
t1.start();
t2.start();
t3.start();
t4.start();
}
}
1. synchronized static method : incrementStaticCounter()
2. synchronized instance method : incrementInstanceCounter()
3. static method를 위한 스레드 t1, t2 생성.
(Example 클래스 자체를 사용하여 static method를 실행하는 스레드)
4. instance method를 위한 스레드 t3, t4 생성.
(Example 클래스의 객체 instance1, instance 2 사용하여 instance method를 실행하는 스레드)
>> 결과
t3, t4 스레드는 각 각 Example 클래스의 인스턴스인 instance1, instance2 를 사용하기에,
개별적인 인스턴스를 사용한 개별적인 스레드 t3, t4가 synchronized instance method를
동시에 실행해서 각기 instanceCounter 변수에 증감연산식이 적용되어 둘 다 같은 값 1을 나타낸다.
반면에 t1, t2 스레드는 Example 클래스 그 자체를 사용하기 때문에
동시에 실행되지 못하고 순차적으로 t1이 끝난 다음 t2가 실행된다.
즉, t1의 메서드 실행으로 staticCounter라는 static 변수의 숫자가 1 증가하여 1이되고,
t2의 메서드 실행으로 staticCounter = 1 변수는 +1이 증가하여 2 라는 값이 된다.
'백엔드 기술 > Java' 카테고리의 다른 글
자료구조 - Stack, Queue 차이점 (0) | 2023.05.15 |
---|---|
얕은 복사 VS 깊은 복사 (0) | 2023.04.27 |
Optional<T> 클래스란 ? (0) | 2023.04.21 |
Multi-Thread & Multi Process (0) | 2023.04.20 |
SingleTon 디자인 패턴 (0) | 2023.04.20 |