Thread synchronized(쓰레드 동기화)

Soozoo·2024년 6월 27일

JAVA

목록 보기
30/41
post-thumbnail

스레드 동기화는 멀티스레딩 환경에서 여러 스레드가 공유 자원에 접근할 때 발생할 수 있는 문제를 해결하기 위한 기법입니다. 동기화는 특정 코드 블록이나 메서드가 동시에 여러 스레드에 의해 실행되지 않도록 보장하는 것입니다. 이를 통해 데이터 일관성을 유지하고, 경합 조건(Race Condition)을 방지할 수 있습니다.

쉽게 예를 들자면, 공유한 폴더에 한 사람씩만 데이터를 집어 넣을 수 있다 치자.
근데 두사람이 한번에 데이터를 집어넣으면 꼬이게 된다. 이런 경우를 방지하기 위해 한 사람이 모든 일을 완료 한 후 다른 사람이 들어가서 작업을 해야된다. 쓰레드 동기화를 통해 해결 할 수 있다.

두가지 방법이 있다.

일단 run()메소드를 찾아라!

syncronized{}로 감싸라!

형식>
public synchronized void deposit(int amount, String name) {
임계영역...
}

public void withdraw(int amount, String name) {
synchronized (this) {
임계영역...
}
}

동기화가 필요한 이유

  1. 공유 자원 접근:
    • 여러 스레드가 동일한 변수나 객체에 접근하여 값을 변경하는 경우, 예상치 못한 결과가 발생할 수 있습니다.
    • 예를 들어, 은행 계좌 잔액을 업데이트하는 작업에서 두 스레드가 동시에 접근하면 잔액이 잘못 계산될 수 있습니다.
  2. 경합 조건(Race Condition):
    • 두 개 이상의 스레드가 동일한 자원에 동시에 접근할 때 발생할 수 있는 문제입니다.
    • 예를 들어, 두 스레드가 같은 변수에 동시에 값을 쓰면, 최종 값이 예상치 못한 결과가 될 수 있습니다.

동기화 방법

자바에서는 synchronized 키워드를 사용하여 메서드나 코드 블록을 동기화할 수 있습니다.

코드 설명

아래 코드는 Atm 클래스를 통해 동기화된 입출금 메서드를 구현하고, 여러 사용자(UserAtm 클래스)가 동시에 ATM 기계를 사용하는 상황을 시뮬레이션합니다.

java코드 복사
package syncronized;

// 쓰레드 (동기화)

class Atm {
    private int money;

    public Atm(int money) { // 생성자 함수
        this.money = money;
    }

    // 입금함수
    public synchronized void deposit(int amount, String name) {
        money += amount;
        System.out.println(name + " : 입금금액 " + amount);
    }

    // 출금함수
    public synchronized void withdraw(int amount, String name) {
        if ((money - amount) > 0) {
            money -= amount;
            System.out.println(name + ": 출금금액 " + amount);
        } else {
            System.out.println(name + ": 출금못함(잔액 부족 ~~~)");
        }
    }

    // 통장 잔고 함수
    public synchronized void getMoney() {
        System.out.println("                            잔액은: " + money);
    }
}// Atm end

class UserAtm extends Thread {
    Atm obj;
    boolean flag = false;

    public UserAtm(Atm obj, String name) {
        super(name);
        this.obj = obj;
    }

    @Override
    public void run() { // 스레드 실행부 (구현부)
        for (int i = 0; i < 2; i++) {
            try {
                sleep(50);
            } catch (Exception e) {
                e.printStackTrace();
            }

            if (flag) {
                obj.deposit((int) (Math.random() * 10 + 2) * 100, getName());
            } else {
                obj.withdraw((int) (Math.random() * 10 + 2) * 100, getName());
            }

            flag = !flag;
            obj.getMoney();
        }
    }
}// UserAtm end

public class MainEntry {
    public static void main(String[] args) {
        Atm at = new Atm(1000);
        UserAtm user1 = new UserAtm(at, "김연아");
        UserAtm user2 = new UserAtm(at, "박태환");
        UserAtm user3 = new UserAtm(at, "세종");

        user1.start();
        user2.start();
        user3.start();
    }
}

코드 설명

  1. Atm 클래스
    • money 변수는 ATM의 잔액을 나타냅니다.
    • deposit 메서드는 입금 기능을 수행하며, synchronized 키워드를 사용하여 동기화됩니다.
    • withdraw 메서드는 출금 기능을 수행하며, synchronized 키워드를 사용하여 동기화됩니다.
    • getMoney 메서드는 현재 잔액을 출력하며, synchronized 키워드를 사용하여 동기화됩니다.
  2. UserAtm 클래스
    • Atm 객체를 참조하는 obj 변수를 가집니다.
    • flag 변수는 입금과 출금을 번갈아 가며 수행하기 위해 사용됩니다.
    • run 메서드는 Thread 클래스의 메서드를 오버라이드하여 스레드의 실행 로직을 정의합니다. 이 메서드에서는 무작위로 입금 또는 출금을 수행하고, 현재 잔액을 출력합니다.
  3. MainEntry 클래스
    • Atm 객체를 생성하고, 이를 공유하는 여러 UserAtm 스레드를 시작합니다.
    • 각 스레드는 start 메서드를 호출하여 실행됩니다.
profile
넙-죽

0개의 댓글