IT/Java

스레드 - (2)

딩딩예 2019. 7. 25. 12:19

4절 동기화 메소드와 동기화 블록

  1. 공유 객체를 사용할 때의 주의할 점

    • 멀티 스레드가 하나의 객체를 공유해서 생기는 오류
  1. 동기화 메소드 및 동기화 블록 - synchronized

    • 단 하나의 스레드만 실행할 수 있는 메소드 또는 블록을 말한다.

    • 다른 스레드는 메소드나 블록이 실행이 끝날 때까지 대기해야한다.

    • 동기화 메소드

     public synchronized void method() {
         임계 영역;     //단 하나의 스레드만 실행
     }
  • 동기화 블록
     public void method() {
         //여러 스레드가 실행 가능 영역

         synchronized(공유 객체) {
             임계영역     //단 하나의 스레드만 실행
         }

         //여러 스레드가 실행 가능 영역

     }

5. 스레드 상태

🍤 스레드 상태

상태 열거 상수 설명
객체 생성 NEW 스레드 객체가 생성, 아직 start() 메소드가 호출되지 않은 상태
실행 대기 RUNNABLE 실행 상태로 언제든지 갈 수 있는 상태
일시 정지 BLOCKED 사용하는 객체의 락이 풀릴 때까지 기다리는 상태
WAITING 다른 스레드가 통지할 때가지 기다리는 상태
TIMED_WAITING 주어진 시간 동안 기다리는 상태
종료 TERMINATED 실행을 마친상태

6. 스레드 상태 제어

🍤 상태 제어

  • 실행 중인 스레드의 상태를 변경하는 것을 말한다.
  • 상태 변화를 가져오는 메소드의 종류
  • 주어진 시간동안 일시정지 - sleep()

    try {
        Thread.sleep(1000);
    } catch(InterruptedException e) {
        //interrupt() 메소드가 호출되면 실행
    }
    
    • 얼마동안 일시 정지 상태로 있을 것인지, 밀리세컨드(1/1000)단위로 지정
    • 일시 정지 상태에서 interrupt() 메소드가 호출되면 InterruptedException 발생
  • 다른 스레드에게 실행 양보 - yield()

  • 다른 스레드의 종료를 기다림 - join()

    • 계산 작업을하는 스레드가 모든 계산 작업을 마쳤을 때, 계산 결과값을 받아 이용하는 경유에 주로 사용
  • 스레드간 협업 - wait(), notify(), notifyAll()

    • 동기화 메소드 또는 블록에서만 호출 가능한 Object의 메소드

    • wait()

      • 호출한 스레드는 일시 정지가 된다.
      • 다른 스레드가 notify() 또는 notifyAll()을 호출하면 실행 대기 상태가 된다.
    • wait(long timeout) / wait(long timeout, int nanos)

      • notify()가 호출되지 않아도 시간이 지나면 스레드가 자동적으로 실행 대기 상태가 된다.
    • 두개의 스레드가 교대로 번갈아 가며 실행해야할 경우 주로 사용

  • 스레드의 안전한 종료(stop 플래그, interrupt())

    • Thread는 스레드를 즉시 종료시키기 위해서 stop()메소드를 제공 - > deprecated 되었다.

      why? stop() 메소드를 사용할 시 스레드가 사용 중이던 자원들이 불안전한 상태로 남겨진다.

  • stop 플래그를 이용하는 방법

    public class PrintThread1 extends Thread {
    
       private boolean stop; //stop 플래그 필드
    
       public void setstop(boolean stop) { 
    
           this.stop = stop;
    
       }
    
       public void run() {
           while(!stop) {
               //스레드가 반복 실행하는 코드;
               System.out.println("실행 중");
           }
           // 스레드가 사용한 자원 정리
           System.out.println("자원 정리");
           System.out.println("실행 종료");
    
       }
    
    }
  • interrupt() 메소드를 이용하는 방법

    :small_blue_diamond: 스레드가 일시정지 상태에 있을 때 InterruptedException예외를 발생시키는 역할

    실행대기 또는 실행 상태에 있을 때 interrupt() 메소드가 실행되면 즉시 예외가 발생되지 않고, 미래에 일시 정지 상태가 되면 예외가 발생한다는 뜻!

  :small_blue_diamond: 일시정지를 만들지 않고도 interrupt() 호출 여부를 알 수 있다.

  ​     interrupt()메소드가 호출되었다면 true를 리턴한다!

  ```java
  //정적메소드로 현재 스레드가 interrupted되었는지 확인하는 것
  boolean status = Thread.interrupted();    

  boolean status = objThread.isInterrupted();    //인스턴스 메소드
  ```

  ```java
  public class PrintThread2 extends Thread { 

      public void run(){
          while(true){
          System.out.println("실행중");
            if(Thread.interrupted()){
              break;        //while문을 빠져나옴

              }

           }

          System.out.println("자원 정리");
          System.out.println("실행 종료");    
      }

  }
  ```

7절 데몬 스레드

  • 주 스레드의 작업을 돕는 보조적인 역할을 수행하는 스레드

  • 주 스레드가 종료되면 데몬 스레드는 강제적으로 자동 종료

    ex) 워드프로세서의 자동저장, 미디어플레이어의 동영상 및 음악 재생, 가비지 컬렉터

  • 데몬 스레드 설정

    • 주 스레드가 데몬이 될 스레드의 setDaemon(true)를 호출

    • 반드시 start() 메소드 호출전에 setDaemon(true)를 호출해야한다.

      -> illegalThreadStateException이 발생

      public static void main(String[] args) {
      
          AutoSaveThread thread = new AutoSaveThread();
          thread.setDaemon(true);
          threaed.start();
      
      }
  • 데몬 스레드 확인 방법
    • isDaemon() 메소드의 리턴값을 조사 데몬 스레드일 경우 true를 리턴한다.

8절 스레드 그룹

관련된 스레드를 묶어서 관리할 목적으로 이용한다.

스레드 그룹은 계층적으로 하위 스레드 그룹을 가질 수 있다.

  • 자동 생성되는 스레드 그룹
    • system 그룹 : JVM 운영에 필요한 스레드를 포함
    • System/main 그룹 : 메인 스레드를 포함
  • 스레드는 반드시 하나의 스레드 그룹에 포함
    • 기본적으로 자신을 생성한 스레드와 같은 스레드 그룹에 속하게 된다.
    • 명시적으로 스레드 그룹에 포함시키지 않으면 기본적으로 system/main 그룹에 속한다.
  • 스레드 그룹 이름 얻기

    ThreadGroup Group = Thread.currentThread().getThreadGroup();
    String groupName = Group.getName();
  • 스레드 그룹 생성

    ThreadGroup tg = new ThreadGroup(String name);
    ThreadGroup tg = new ThreaedGroup(ThreadGroup parent, String name);
    • 부모(parent) 그룹을 지정하지 않으면 현재 스레드가 속한 그룹의 하위 그룹으로 생성
    • 스레드를 그룹에 명시적으로 포함시키는 방법
  • 스레드 그룹의 일괄 interrupt()
    • 스레드 그룹의 interrupt()를 호출하면 소속된 모든 스레드의 interrupt()가 호출된다.
  • 스레드 그룹의 list()메소드 출력 내용

    ThreadGroup mainGroup = Thread.currentThread.getThreadGroup();
    mainGroup.list();