본문 바로가기

Java/Java

(JAVA) 쓰레드 동기화

  • 싱글쓰레드 프로세스의 경우에는 프로세스 내에서 단 하나의 쓰레드 만을 구현하니 프로세스의 자원을 가지고 작업하는데 별 다른 문제가 없다.
  • 하지만 멀티쓰레드 프로세스의 경우에는 여러 쓰레드가 하나의 프로세스를 공유하기 때문에 자원 공유에 있어서 많은 문제가 발생할 수 있다.

가령 쓰레드 A가 있다고 가정하자 처리 도중 쓰레드 B가 제어권을 넘겨받아 처리한다면

쓰레드 A는 자신이 예상하는 결과를 갖지 못할 것이다.

 

https://jwdeveloper.tistory.com/123?category=823919

 

(JAVA) 쓰레드의 개요 (1)

프로세스와 Thread 프로세스는 실행 중인 프로그램이고 OS로부터 실행에 필요한 자원을 할당받아 프로세스가 실행된다. 프로세스의 자원을 이용해서 실제로 작업을 수행하는 대상이 Thread이다. 모든 프로세스에..

jwdeveloper.tistory.com

이러한 이유로 도입된 개념이 임계 영역(critical section) , 락(lock)이다.

 

  1. 공유 데이터를 사용하는 코드의 영역을 임계 영역으로 지정 - 이때 공유 데이터는 객체
  2. 객체가 가지고 있는 lock을 획득한 단 하나의 Thread 만이 임계 영역의 코드를 수행 가능
  3. lock을 반납하고 해당 lock을 획득한 그다음 Thread가 또다시 코드를 수행한다.

synchronized를 이용한 동기화

예제 코드

 

잔고가 비어있지 않을 때 인출 

public class SynchronizedEx2 implements Runnable{
    Account account = new Account();

    @Override
    public void run() {
        while (account.getBalance() > 0) {
            int money = (int) (Math.random() * 3 + 1) * 100;
            account.withdraw(money);
            System.out.println("balance : "+ account.getBalance());
        }
    }
}

잔고는 1000이고 인출하려는 금액이 현재 잔고보다 적거나 같을 때만 인출 가능

public class Account {
    private int balance = 1000;

    public int getBalance() {
        return balance;
    }

    public void withdraw (int money) {
        if (balance >= money) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {

            }
            balance -= money;
        }
    }
}

하나의 프로세스에 두 개의 쓰레드를 돌린다.

public class SynchronizedEx {
    public static void main(String[] args) {
        Runnable runnable = new SynchronizedEx2();
        new Thread(runnable).start();
        new Thread(runnable).start();
    }
}

실행 결과

인출하려는 금액이 현재 잔고보다 적거나 같을 때만 인출 가능하다고 했는데 잔고는 -100이다.

 

이유는 if 조건을 통과하기 직전에 다른 Thread가 끼어들어 인출을 하였기 때문이다. if를 통과한 직후 이기 때문에 막을 방법이 없는 것이다.

 


해결 방법 : synchronized 키워드를 붙여서 임계 영역을 지정하자

public synchronized void withdraw (int money) {
    if (balance >= money) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {

        }
        balance -= money;
    }
}

실행 결과


코드 참조

https://github.com/mike6321/PURE_JAVA/tree/master/Thread

 

mike6321/PURE_JAVA

Contribute to mike6321/PURE_JAVA development by creating an account on GitHub.

github.com