JAVA/JAVA 기본

JAVA Thread

엔테아 2017. 10. 11. 18:45

Thread

동시에 실행해야 하는 일이 있을 때 스레드를 사용함

메인스레드

│

│

│

│

│

│

↓

사용자

생성스레드 

│

│

│

│

│

│

↓

사용자

생성스레드

클래스

클래스

클래스

스택

스택

스택

힙

힙

힙

 

스레드끼리는 클래스 및 힙영역의 데이터를 주고받을 수 있음

단. 스택영역의 데이터는 주고받을 수 없음

 

스레드끼리는 데이터를 주고받는 과정에서 오류가 발생할 수 있으며,

이는 스레드 동기화를 통하여 해결하여야 한다.

 

Thread ct = Thread.currentThread();

String tName = ct.getName();
System.out.println(tName);

 

스레드ct에 현재 사용중인 스레드를 받아와, tName에 그 스레드의 이름값을 투입하여 출력함.

 

스레드의 구현

스레드 클래스 생성 - 스레드 객체 생성 - 스레드 생성

 

스레드 생성 방법

 

1. Thread 클래스를 상속(extends)하는 클래스를 이용

ㄴ 소스 - 오버라이드/임플리먼츠 메서드 - run()을 오버라이드하여 사용

ㄴ 스레드클래스명 변수명 = new 스레드클래스명

ㄴ 변수명.start(); -현재 시점에서 스레드가 생성됨

 

2. Runnable인터페이스를 구현(implements)하는 클래스를 이용

ㄴ 스레드클래스명 러너블변수명 = new 스레드클래스명

ㄴ Thread 변수명 = new Thread(러너블변수명);

 

스레드의 생애

1. 스레드 생성(start() 호출)

2. runnable상태

3. running 상태

ㄴ Thread.sleep();등을 만나면 Blocked 상태로 변경

ㄴ 블락상태의 스레드는 블락이 끝난 후 러너블상태로 돌아감

4. 스레드 종료(Dead상태)

 

스레드 동기화

1. join()메서드

ㄴ join()메서드를 호출한 스레드의 작업이 끝날때까지 현재의 스레드는 작업을 멈춘다.

ㄴ 메인스레드에서 t1.join();으로 호출할 시, t1스레드의 작업이 종료될때까지 메인스레드의 작업이 멈춤

ㄴ

메인스레드 이외에의 스레드 동기화 방법

ex) 스레드 a가 끝날때까지 스레드 b를 멈춰라!

멈춰야 할 스레드 bbbbbbbbbbbaaaabbbbbbbbbbbbb인 타임라인이 그려짐.

이 경우 스레드b에서 작업을 시행해야 함.

스레드 b에서 a.join();을 선언함

a.join();을 선언하기 위해서 인스턴스변수

Thread a;를 선언

Thread a;를 선언하고, 사용하기 위해서 사용자 생성자(컨스트럭터 유징필드)를 선언해줌.

사용자 생성자를 선언하였음. 해당 사용자 생성자를 사용하였으니 스레드 b에 a값을 넣어줌

ChildThread3 rt3 = new ChildThread3(a);

 

 

 

 

메인 스레드

package kr.co.joeun;

public class MainEx {
     public static void main(String[] args) {

          ChildThread at1 = new ChildThread(); //스레드 1을 만듦 //스레드1은 스레드 상속
          t1.start();

          ChildThread3 rt3 = new ChildThread3(at1); //스레드 3을 만들 때 스레드 1을 넣어줌 //스레드3은 임플리먼츠 러너블
          Thread at3 = new Thread(rt3);
          t3.start();

     }

}

멈추어야 할 스레드

package kr.co.joeun;

public class ChildThread3 implements Runnable {


     Thread t1; //스레드 1호출(스레드 1은 스레드 3을 멈춘 동안 작동할 스레드) 

     public ChildThread3(Thread t1) {
          super();
          this.t1 = t1;
     } //스레드 1의 사용자 생성자(컨스트럭터 유징필드)

 

     @Override
     public void run() {
          try {
               t1.join();
          } catch (InterruptedException e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
          }

     } //t1.join의 트라이캐치

}

상기 표의 설명

1. 스레드 at3의 생성자에 요구되는 값 t1

2. 스레드 at3의 변수 t1에  메인클래스에서 스레드 at1값을 넣어줌.

3. 스레드 at3이 실행되는 중 at1에서 (스레드3의 변수)t1을 거친 스레드at1이 join();을 요청함.

4. 스레드 at3은 잠시 중지되고 스레드at1이 실행됨

 

 

데이터의 동기화(하나의 작업을 입/출력까지 하나로 묶어서 처리하는 것)를 임계영역별로 나누어 동기화 처리

해당 동기화 처리는

메서드를 syncronized 처리함.

public syncronized void me1(){}

 

동기화 블럭의 사용법

메서드 내부의 영역에 서라운드위드 - 싱크로나이즈드 - mutax를 this로 수정, 또는 Object obj = new Object(); 등의 선언 이후 obj를 넣어서 동기화 블럭의 열쇠로 활용

public void plusNum(int add) {
     synchronized (this) {
          num += add;
     }
}

등의 방식으로 사용

 

접근순서에 대한 동기화

 

if문, try~catch, 동기화 블록, notify(); , waiting(); 등의 문법을 사용

 

if문을 통하여 wait();를 실행할 지 정하고, wait문은 싱크로나이즈드로 감싸줌(서라운드 위드-싱크로나이즈드)

 

notify();가 실행되면 wait();문에 의한 대기를 끝냄. notify문 역시 싱크로나이즈드로 감싸줌.

 

작가가 글을 올리면 독자가 읽는다!

일 때, 독자가 먼저 글을 읽기 위해 접근할 경우 wait문으로 정지시키고

작가가 글을 올리면 notify문으로 독자의 wait를 해제시켜 주는 형식.

 

 

익명으로 만든 스레드

     new Thread(new Runnable() {
          @Override
          public void run() {
               // TODO Auto-generated method stub
               System.out.println("익명으로 만든 스레드");
          }
     }).start();