본문 바로가기

미국유학/CS 601 Principles of Software Dev

10.4 Lock

`static lock`은 멀티스레드 환경에서 클래스 레벨에서 동기화를 위해 사용되는 개념입니다. 주로 Java에서 `static` 키워드를 사용하여 클래스에 대한 공유 자원을 여러 스레드가 동시에 접근하는 것을 막기 위해 동기화(synchronization)를 합니다.

### `static lock` 개념
1. **클래스 레벨 동기화**: 
   - `static lock`은 특정 인스턴스가 아닌 **클래스 자체에 대한 동기화**를 의미합니다.
   - `static synchronized` 메서드 또는 `synchronized(staticLock)`과 같은 블록은 클래스 레벨의 잠금을 획득하여 동기화됩니다. 이 말은 **클래스의 모든 인스턴스가 동일한 락을 공유**한다는 뜻입니다.
   
2. **공유 리소스 보호**:
   - `static lock`은 클래스가 공유하는 리소스에 대한 동시 접근을 제어하기 위해 사용됩니다. 예를 들어, **static 변수**에 여러 스레드가 동시에 접근하는 상황에서 데이터를 일관성 있게 보호할 수 있습니다.

### 예시 코드

```java
public class StaticLockExample {

    private static int counter = 0;  // 공유 자원
    private static final Object staticLock = new Object();  // static lock 객체

    // static synchronized method 사용
    public static synchronized void incrementCounter() {
        counter++;
    }

    // static synchronized block 사용
    public static void incrementWithStaticLock() {
        synchronized (staticLock) {
            counter++;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                incrementCounter();
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                incrementWithStaticLock();
            }
        });

        t1.start();
        t2.start();
        t1.join();
        t2.join();

        System.out.println("Final counter value: " + counter);  // 일관된 값 보장
    }
}
```

### 주요 포인트
1. **`static synchronized method`**: 해당 메서드는 클래스 레벨에서 잠금을 걸어 한 번에 하나의 스레드만 접근할 수 있도록 합니다. 클래스 자체에 동기화가 적용됩니다.
   
2. **`synchronized(staticLock)`**: 이 방법은 **클래스 전체에 걸쳐 하나의 객체(staticLock)**를 잠금으로 사용하여 명시적으로 동기화 블록을 구현합니다.

### `static lock`을 사용하는 이유
- **공유 리소스 보호**: 클래스에 있는 공유 변수를 여러 스레드가 동시에 변경하면 데이터가 일관되지 않을 수 있습니다. 이를 방지하기 위해 `static lock`을 사용하여 동기화합니다.
- **클래스 레벨 동기화**: 여러 스레드가 특정 클래스의 인스턴스와 상관없이 **클래스 자체**에서 공유되는 자원(예: `static 변수`)에 접근할 때, 안전한 동시성 제어를 하기 위함입니다.

이러한 `static lock`을 통해 **멀티스레딩 환경에서의 안전한 데이터 보호**와 **경쟁 상태(race condition)**를 방지할 수 있습니다.

 

 

==================================================================

이 코드에서는 **멀티스레드 환경에서의 동기화(synchronization) 및 락(lock)**이 어떻게 동작하는지를 보여줍니다. 여러 종류의 락을 사용하여 스레드들이 동시에 실행될 수 있는지(혹은 서로 경쟁하는지)를 시뮬레이션하고 있습니다. 이 예제는 **스레드들이 동시에 실행될 수 있는지, 아니면 락 때문에 순차적으로 실행되는지**를 보여줍니다.

### 주요 구성 요소

1. **`Thread` 클래스 확장 (`Worker`)**
   - `Worker`는 각각의 작업을 처리할 스레드를 정의한 내부 클래스입니다.
   - 이 클래스는 `run` 메서드 안에서 `synchronized(lock)` 블록을 사용하여 락을 걸고 동기화된 작업을 수행합니다.
   - 이 락(lock)은 **임의의 객체(Object)**를 사용할 수 있으며, 해당 객체에 대한 락이 걸린 상태에서는 다른 스레드가 이 블록에 접근하지 못합니다.

2. **다양한 종류의 락 사용 (`outerLock`, `multiLock`, `staticLock`)**
   - **`outerLock`**: 인스턴스마다 고유한 락 객체입니다.
   - **`multiLock`**: 또 다른 인스턴스 락 객체입니다.
   - **`staticLock`**: **클래스 레벨**에서 사용하는 **정적 락(static lock)**으로, 모든 인스턴스가 공유합니다.

3. **스레드 생성 및 동작**
   - `worker1`과 `worker2`라는 두 개의 스레드를 사용하여 동시에 작업을 처리합니다.
   - 각각의 스레드는 `Worker` 클래스를 사용하여 스레드가 실행될 때 동기화된 방식으로 락을 걸고 동작합니다.

### 코드 동작 흐름

- `LockDemo` 클래스는 두 개의 스레드(`worker1`과 `worker2`)를 시작하여 특정 작업을 수행합니다.
- `synchronized(lock)` 블록은 각 스레드가 동기화된 방식으로 락을 걸고 안전하게 작업을 처리할 수 있게 합니다.
- `Thread.sleep(1000)`은 1초 동안 스레드가 유지되면서 해당 락을 가지고 있다는 것을 의미합니다. 즉, 이 스레드가 락을 점유하는 동안 다른 스레드들은 이 락을 기다리게 됩니다.

### 락(lock)의 종류에 따른 동작 방식

코드에서 주석 처리된 여러 부분에서 다양한 락 전략을 선택할 수 있으며, 이들에 따라 스레드들이 동시에 실행될 수 있는지 또는 순차적으로 실행될지를 결정합니다.

1. **서로 다른 락 사용 (TT TT FF FF)**:
   - `worker1`과 `worker2`는 각각 다른 락(`outerLock`과 `multiLock`)을 사용하므로 서로 락을 경쟁하지 않고 동시에 실행될 수 있습니다.
   
2. **같은 락 사용 (TT FF TT FF)**:
   - 두 스레드가 같은 락(`outerLock`)을 공유할 경우, 두 스레드는 동일한 락을 얻기 위해 경쟁합니다. 한 스레드가 락을 점유하면, 다른 스레드는 락이 해제될 때까지 대기해야 합니다.

3. **static 락 사용 (TF TF TF TF)**:
   - `staticLock`은 **클래스 전체에서 공유되는 락**이므로, 모든 인스턴스의 스레드가 이 락을 경쟁합니다. 여러 스레드가 동시에 실행되지 않고, 하나의 스레드가 끝날 때까지 다른 스레드는 대기하게 됩니다.

4. **새로운 객체마다 락 사용 (TT TT FF FF)**:
   - 스레드마다 새로운 객체로 락을 사용하면, 각 스레드는 독립적인 락을 가지게 되어 서로 간섭하지 않고 동시에 실행될 수 있습니다.

### 주요 포인트
- **락(lock)**은 특정 자원(객체)에 대해 동기화하여, 하나의 스레드만 접근할 수 있도록 제한하는 장치입니다. 락을 사용하면 여러 스레드가 동시에 같은 자원에 접근하면서 발생할 수 있는 문제를 방지할 수 있습니다.
- 이 코드에서는 다양한 락을 사용하여 스레드 동작 방식을 실험할 수 있습니다. 락이 서로 다르면 스레드가 동시에 실행될 수 있지만, 같은 락을 사용하면 하나의 스레드가 끝날 때까지 다른 스레드는 대기해야 합니다.

 

==================================================================

A1,B1 이 먼저 출력되고 A2,B2 가 출력되는 경우에 대해서 설명해줄래??? A2,B1,A1,B2 순서 출력되는 경우와 차이를 알려줘 

이 두 가지 시나리오는 **멀티스레드** 프로그램에서 스레드가 어떻게 실행되고, 어떻게 락(lock)에 접근하는지에 따라 달라집니다. 스레드 실행 순서와 락의 경쟁 상황에 의해 각 스레드의 작업이 완료되는 순서가 결정됩니다.

### 1. **A1, B1이 먼저 출력되고 A2, B2가 출력되는 경우**
이 경우는 각 스레드(A1, B1, A2, B2)가 다른 락을 사용하거나, 서로 경쟁하지 않는 락을 사용할 때 발생합니다. 즉, 스레드 A1과 B1은 동시에 실행될 수 있는 상황이며, A2와 B2는 그 다음에 실행됩니다.

이 상황은 **서로 다른 락**을 사용하는 경우에 발생할 수 있습니다.

#### 예시:
- `A1` 스레드는 `outerLock`을 사용하고, `B1` 스레드는 `multiLock`을 사용합니다.
- `A1`과 `B1`은 각기 다른 락을 사용하기 때문에 서로 락을 두고 경쟁하지 않습니다.
- 그래서 `A1`과 `B1`이 동시에 실행될 수 있습니다.
- 그 후 `A2`와 `B2`가 차례로 실행됩니다.

### 2. **A2, B1, A1, B2 순서로 출력되는 경우**
이 경우는 스레드가 **동일한 락**을 사용하거나, **동일한 자원에 대한 락을 기다리는 상황**이 있을 때 발생할 수 있습니다. 스레드 간의 **경쟁**이 발생하면서, 스레드가 락을 얻기 위해 대기하다가 실행 순서가 달라집니다.

#### 예시:
- `A1`과 `B1`이 같은 락(예: `staticLock` 또는 `outerLock`)을 공유하고 있다면, 두 스레드는 락을 얻기 위해 경쟁합니다.
- 이 경우, `B1`이 먼저 락을 획득하면 `A1`은 락이 해제될 때까지 대기합니다.
- `B1`이 락을 해제한 후, `A1`이 그제서야 실행될 수 있습니다.
- 동시에 `A2`와 `B2`도 동일한 락을 두고 경쟁할 수 있으며, 스레드가 대기하는 동안 실행 순서가 바뀔 수 있습니다.

즉, 두 번째 시나리오는 **경쟁 조건(컨텐션)**이 발생하면서 스레드가 **순차적으로 실행되지 않는** 상황을 나타냅니다.

### 차이점 요약
1. **A1, B1 먼저 출력, 그 후 A2, B2**
   - 각 스레드(A1, B1)가 **다른 락**을 사용하여 서로 간섭하지 않고 동시에 실행됩니다.
   - A1, B1이 먼저 실행되고 나서 A2, B2가 실행됩니다.
   - 즉, **경쟁 없이 독립적으로** 실행됩니다.

2. **A2, B1, A1, B2 순서**
   - 스레드들이 **같은 락**을 사용하거나 **경쟁**하는 상황에서 발생할 수 있습니다.
   - 어떤 스레드는 먼저 락을 얻고, 다른 스레드는 그 락이 해제될 때까지 대기합니다.
   - **경쟁**에 의해 실행 순서가 달라지며, 이는 락을 얻는 타이밍에 따라 결과가 달라집니다.

스레드들이 언제 락을 얻고, 언제 해제하는지에 따라 실행 순서가 달라지며, 그 결과로 서로 다른 출력 순서가 발생하게 됩니다.

 

 

 

 

 

 

'미국유학 > CS 601 Principles of Software Dev' 카테고리의 다른 글

241003 PSD - Multithreading, Synchronization  (2) 2024.10.04
241001 수업 , Thread  (0) 2024.10.02
Polymorphism (240905)  (0) 2024.09.06
240903 Iterator  (0) 2024.09.04
1st quiz  (0) 2024.08.30