본문 바로가기

라이브러리 활용 - 멀티 스레드

스레드 동기화

동기화 메소드와 블록

  • 스레드 작업이 끝날 때까지 객체에 잠금을 걸어 스레드가 사용 중인 객체를 다른 스레드가 변경할 수 없게 함


    출처, 이것이 자바다



    출처, 이것이 자바다


동기화 메소드 및 블록 선언

  • 인스턴스와 정적 메소드에 synchronized 키워드 붙임


    출처, 이것이 자바다


  • 동기화 메소드를 실행 즉시 객체는 잠금이 일어나고, 메소드 실행이 끝나면 잠금 풀림
  • 메소드 일부 영역 실행 시 객체 잠금을 걸고 싶다면 동기화 블록을 만듦


    출처, 이것이 자바다


package ch14.sec06.exam01;

//공유객체
public class Calculator {

    //공유필드
    private int memory;

    public int getMemory() {
        return memory;
    }

    //synchronized : 메소드에 동기화 작업. synchronized 유무에 따른 테스트 해보기
    //동기화 메소드
    public synchronized void setMemory1(int memory) {
        this.memory = memory;

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {}

        System.out.println(Thread.currentThread().getName() + ": " + this.memory);
    }

    //불록 동기화 : 메소드내에서 일부 코드만 다른 스레드의 접근을 막을때 사용.
    public void setMemory2(int memory) {
        synchronized (this) {
            this.memory = memory;

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {}

        System.out.println(Thread.currentThread().getName() + ": " + this.memory);
    }
  }
}

package ch14.sec06.exam01;

public class User1Thread extends Thread {

    private Calculator calculator;

    public User1Thread() {
        setName("User1Thread");
    }

    public void setCalculator(Calculator calculator) {
        this.calculator = calculator;
    }

    @Override
    public void run() {
        calculator.setMemory1(100);
    }
}

package ch14.sec06.exam01;

public class User2Thread extends Thread {

    private Calculator calculator;

    public User2Thread() {
        setName("User2Thread");
    }

    public void setCalculator(Calculator calculator) {
        this.calculator = calculator;
    }

    @Override
    public void run() {
        calculator.setMemory2(50);
    }
}

package ch14.sec06.exam01;

/*
 스레드 : 동기화 예제
  - 메인 스레드, user1Thread 스레드, user2Thread 스레드
 */

public class SyncronizedExample {

    public static void main(String[] args) {

        //스레드1, 2가  calculator1, calculator2 객체를 생성할 경우에는 동기화 작업이 필요가 없다. 
        //이유는 기억장소를 동시에 접근하는 상황이 발생되지 않기때문.
//        Calculator calculator1 = new Calculator();
//        Calculator calculator2 = new Calculator();

        //공유자원으로 사용한 클래스 객체. 스레드1, 2가 동시에 사용할 객체.
        Calculator calculator = new Calculator();

        //스레드 객체 생성
        User1Thread user1Thread = new User1Thread();
        user1Thread.setCalculator(calculator);
        user1Thread.start();

        User2Thread user2Thread = new User2Thread();
        user2Thread.setCalculator(calculator);
        user2Thread.start();
    }
}


출처, 이것이 자바다


wait( )과 notify( )를 이용한 스레드 제어

  • 두 스레드 교대 실행 시 공유 객체는 두 스레드가 작업할 내용을 각각 동기화 메소드로 정함
  • 한 스레드 작업 완료 시 notify() 메소드를 호출해 일시 정지 상태에 있는 다른 스레드를 실행 대기 상태로 만들고, wait() 메소드를 호출하여 자신은 일시 정지 상태로 만듦


    출처, 이것이 자바다


  • notify(): wait()에 의해 일시 정지된 스레드 중 한 개를 실행 대기 상태로 만듦
  • notifyAll(): wait()에 의해 일시 정지된 모든 스레드를 실행 대기 상태로 만듦
package ch14.sec06.exam02;

//공유객체
public class WorkObject {

    //작업1.  예>생산자
    public synchronized void methodA() {
        Thread thread = Thread.currentThread(); //이 코드를 실행하는 실행스레드 참조.
        System.out.println(thread.getName() + ": methodA 작업 실행");
        notify(); //일시정지중인 소비자 스레드를 실행대기상태로 변경.
        try {
            wait(); //자신의 스레드를 일시정지상태
        } catch (InterruptedException e) {} 
    }

    //작업2.  예>소비자
    public synchronized void methodB() {
        Thread thread = Thread.currentThread(); //이 코드를 실행하는 실행스레드 참조.
        System.out.println(thread.getName() + ": methodB 작업 실행");
        notify(); //일시정지중인 생산자 스레드를 실행대기상태로 변경.
        try {
            wait(); //자신의 스레드를 일시정지상태
        } catch (InterruptedException e) {}
    }    
}

package ch14.sec06.exam02;

//작업1 : 생산자 스레드
public class ThreadA  extends Thread{
    private WorkObject workObject;

    public ThreadA(WorkObject workObject) {
        setName("ThreadA");
        this.workObject = workObject;
    }

    @Override
    public void run() {
        for(int i=0; i<10; i++) {
            workObject.methodA();
        }
    }
}

package ch14.sec06.exam02;

//작업1 : 소비자 스레드
public class ThreadB  extends Thread{
    private WorkObject workObject;

    public ThreadB(WorkObject workObject) {
        setName("ThreadB");
        this.workObject = workObject;
    }

    @Override
    public void run() {
        for(int i=0; i<10; i++) {
            workObject.methodB();
        }
    }
}

package ch14.sec06.exam02;

/*
 스레드 동기화 : 생산자, 소비자

 스레드 : 메인 스레드, threadA, threadB

 실행시 notify(), wait() 코드 유무에 따라 실행결과를 확인해야 한다.
 */

public class WaitNotifyExample {

    public static void main(String[] args) {
        WorkObject workObject = new WorkObject();

        ThreadA threadA = new ThreadA(workObject);
        ThreadB threadB = new ThreadB(workObject);

        threadA.start();
        threadB.start();        
    }
}

'라이브러리 활용 - 멀티 스레드' 카테고리의 다른 글

데몬 스레드  (1) 2023.02.06
스레드 안전 종료  (1) 2023.02.06
스레드 상태  (1) 2023.02.03
스레드 이름  (0) 2023.02.03
작업 스레드 생성과 실행  (1) 2023.02.03