LostCatBox

Java 배우기 CH13

Word count: 946Reading time: 5 min
2022/12/23 Share

쓰레드

프로세스와 쓰레드

  • 프로세스: 실행 중인 프로그램, 자원(resources)과 쓰레드로 구성
  • 쓰레드: 프로세스 내에서 실제 작업을 수행
    모든 프로세스는 최소한 하나의 쓰레드를 가지고있다.
  • 하나의 새로운 프로세스를 생성하는 거보다 하나의 새로운 쓰레드를 생성해주는 것이 더 적은 비용이 든다

Untitled

Untitled

  • 단점
    • 동기화
    • 교착상태
    • 기아(실행할기회없음)

쓰레드의 구현과 실행

  • 자바는 단일 상속! 따라서 인터페이스 구현이 더.. 좋을수도
  • 클래스 상속받기
  • 인터페이스 구현

Untitled

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Ex13_1 {
public static void main(String args[]) {
ThreadEx1_1 t1 = new ThreadEx1_1();

Runnable r = new ThreadEx1_2();
Thread t2 = new Thread(r); // 생성자 Thread(Runnable target) //run()이 구현되어있는 인터페이스 받

t1.start();
t2.start();
}
}

class ThreadEx1_1 extends Thread {
public void run() {
for(int i=0; i < 5; i++) {
System.out.println(getName()); // 조상인 Thread의 getName()을 호출 // this.getName()이며, 상속받았음!!
}
}
}

class ThreadEx1_2 implements Runnable {
public void run() {
for(int i=0; i < 5; i++) {
// Thread.currentThread() - 현재 실행중인 Thread를 반환한다.
System.out.println(Thread.currentThread().getName());
}
}
}

쓰레드의 실행 - start()

  • 쓰레드를 생성한 후에 start()를 호출해야 쓰레드가 작업을 시작한다. 하지만 OS스케줄러가 실행 순서 결정하므로 순서 보장안됨. start()하자마자 바로 실행아님

  • t1.start()
    t2.start()

  • start()와 run()차이
    결국 start()을 해야 새로운 호출스택을 생성후 run()을 돌린다

Untitled

main쓰레드

  • main메서드의 코드를 수행하는 쓰레드
  • 쓰레드는 “사용자 쓰레드”와 “데몬 쓰레드” 두 종류가있다.
    데몬 쓰레드==보조 쓰레드
  • 실행 중인 사용자 쓰레드가 하나도 없을 때 프로그램은 종료된다.
  • 즉, main 쓰레드가 종료되어도 run 쓰레드가 실행중이므로 프로그램 종료안됨!!

Untitled

싱글쓰레드와 멀티쓰레드

  • 그림과 다르게 멀티쓰레드는 OS스케줄러에 따라 길이가 다를수있음.

Untitled

쓰레드의 I/O 블락킹(blocking)

  • 외부장치의 입력 출력

Untitled

쓰레드의 우선순위(priority of thread)

  • 작업의 중요도에 따라 쓰레드의 우선순위를 다르게 하여 특정 쓰레드가 더 많은 작업시간을 갖게 할수 있다.
  • setPriority(int ) (기본순위 5)
  • getPriority( )

Untitled

하지만 현실은 OS스케줄러에 반드시 희망사항대로 되지않는다.

1
2
3
4
5
6
7
8
9
10
11
12
13
class Ex13_6 {
public static void main(String args[]) {
ThreadEx6_1 th1 = new ThreadEx6_1();
ThreadEx6_2 th2 = new ThreadEx6_2();

th2.setPriority(7);

System.out.println("Priority of th1(-) : " + th1.getPriority());
System.out.println("Priority of th2(|) : " + th2.getPriority());
th1.start();
th2.start();
}
}

쓰레드 그룹

  • 서로 관련된 쓰레드를 그룹으로 묶어서 다루기 위한것
  • 모든 쓰레드는 반드시 한의 쓰레드 그룹에 포함되어있어야한다
  • 쓰레드 그룹을 지정하지 않고 생성한 쓰레드는 main쓰레드 그룹에 속한다
  • 자신을 생성한 쓰레드(부모 쓰레드)의 그룹과 우선순위를 상속받는다

Untitled

쓰레드 그룹의 메서드

Untitled

데몬 쓰레드(daemon thread)

  • 일반 쓰레드(non-daemon thread)의 작업을 돕는 보조적인 역할을 수행
  • 일반 쓰레드가 모두 종료되면 자동적으로 종료된다
  • 가비지 컬렉터, 자동저장, 화면 자동갱신 등에 사용된다.
  • 무한루프와 조건문을 이용해서 실행 후 대기하다가 특정조건이 만족되면 작업을 수행하고 다시 대기하도록 작성한다.

Untitled

  • setDaemon()은 반드시 start()호출하기 전에 실행되어야한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Ex13_7 implements Runnable  {
static boolean autoSave = false;

public static void main(String[] args) {
Thread t = new Thread(new Ex13_7()); //Thread(Runnable r)Runnable인터페이스 받은 클래스
t.setDaemon(true); // 이 부분이 없으면 종료되지 않는다.
t.start();

for(int i=1; i <= 10; i++) {
try{
Thread.sleep(1000);
} catch(InterruptedException e) {}
System.out.println(i);

if(i==5) autoSave = true;
}

System.out.println("프로그램을 종료합니다.");
}

public void run() {
while(true) {
try {
Thread.sleep(3 * 1000); // 3초마다
} catch(InterruptedException e) {}

// autoSave의 값이 true이면 autoSave()를 호출한다.
if(autoSave) autoSave();
}
}

public void autoSave() {
System.out.println("작업파일이 자동저장되었습니다.");
}
}

쓰레드의 상태

Untitled

쓰레드의 실행제어

  • 쓰레드의 실행을 제어할 수 있는 메서드가 제공된다
  • 이 들을 활용해서 보다 효율적인 프로그램의 작성할 수 있다.
  • static 메서드는 자기 자신에게만 호출가능

Untitled

Tread 실행제어 static 메서드

  • sleep() 잠
  • yield() 양보

(static) sleep()

  • 현재 쓰레드를 지정한 시간동안 멈추게 한다. (this.sleep()임)
  • 예외처리를 해야한다.(InterruptedException이 발생하면서 깨어남) (깨어나는것은 time up 또는 interrupted밖에없다)
  • 특정 쓰레드를 지정해서 멈추게 하는 것은 불가능하다.

Untitled

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Ex13_8 {
public static void main(String args[]) {
ThreadEx8_1 th1 = new ThreadEx8_1();
ThreadEx8_2 th2 = new ThreadEx8_2();
th1.start(); th2.start();

try {
th1.sleep(2000); //th1을2초동안 잠자는게아니라, main이 잠을잠. 실행시키는자가
//따라서 th1.sleep()아니라 Thread.sleep()이 올바른 표
} catch(InterruptedException e) {}

System.out.print("<<main 종료>>");
} // main
}

class ThreadEx8_1 extends Thread {
public void run() {
for(int i=0; i < 300; i++) System.out.print("-");
System.out.print("<<th1 종료>>");
} // run()
}

class ThreadEx8_2 extends Thread {
public void run() {
for(int i=0; i < 300; i++) System.out.print("|");
System.out.print("<<th2 종료>>");
} // run()
}

interrupt()

  • 대기상태(WAITING)인 쓰레드를 실행대기 상태(RUNNABLE)로 만든다
  • interrupt()는 해당 쓰레드클래스의 iv의 interrupted의 값을 변화시킴
  • static interrupted()는 static이므로 지금 돌아가는 것의 interrupted여부를 확인하는것임!!!!!

Untitled

suspend(), resume(), stop()

  • 쓰레드의 실행을 일시정지, 재개, 완전정지 시킨다.
  • 하지만 위의 함수보두 deprecated 이므로 권장 사용 안함!!

Untitled

Untitled

join()

  • 지정된 시간동안 특정 쓰레드가 작업하는 것을 기다린다
  • 예외처리를 해야한다.(InterruptedException이 발생하면 작업 재개)

Untitled

Untitled

yield()

  • 남은 시간을 다음 쓰레드에게 양보하고, 자신(현재 쓰레드)은 실행대기한다.
  • yield()와 interrupt()를 적절히 사용하면, 응답성과 효율을 높일 수있다. >> yield()는 OS스케줄러에게 의견제시하는거임(반드시X)

Untitled

쓰레드의 동기화(synchronization)

  • 멀티 쓰레드 프로세스에서는 다른 쓰레드의 작업에 영향을 미칠 수 있다.
  • 진행중인 작업이 다른 쓰레드에게 간섭받지 않게 하려면 동기화 필요(한 쓰레드가 진행중인 작업을 다른 쓰레드가 간섭하지못하도록함)
  • 동기화하려면 간섭받지 않아야하는 문장들을 “임계 영역”으로 설정
  • 임계영역은 락(lock)을 얻은 단 하나의 쓰레드만 출입가능(객체 1개에 락 1개)
  • 해당 객체와 관련된 곳은 모두 동기화해야함

synchronized를 이용한 동기화

  • synchronized로 임계여역(lock이 걸리는 영역)을 설정하는 방법2가지Untitled 20

  • 예제

Untitled

wait()와 notify()

  • 동기화의 효율을 높이기 위해 wait(), notify()를 사용
  • Object클래스에 정의되어 있으며, 동기화 블록 내에서만 사용할수있다.
  • wait() - 객체의 lock을 풀고 쓰레드를 해당 객체의 waiting pool에 넣는다
  • notify() - waiting pool에서 대기중인 쓰레드 중의 하나를 깨운다
  • notifyAll() - waiting pool에서 대기중인 모든 쓰레드를 깨운다
CATALOG
  1. 1. 쓰레드
    1. 1.1. 프로세스와 쓰레드
    2. 1.2. 쓰레드의 구현과 실행
    3. 1.3. 쓰레드의 실행 - start()
    4. 1.4. main쓰레드
    5. 1.5. 싱글쓰레드와 멀티쓰레드
    6. 1.6. 쓰레드의 I/O 블락킹(blocking)
    7. 1.7. 쓰레드의 우선순위(priority of thread)
    8. 1.8. 쓰레드 그룹
      1. 1.8.1. 쓰레드 그룹의 메서드
    9. 1.9. 데몬 쓰레드(daemon thread)
    10. 1.10. 쓰레드의 상태
    11. 1.11. 쓰레드의 실행제어
    12. 1.12. Tread 실행제어 static 메서드
    13. 1.13. (static) sleep()
    14. 1.14. interrupt()
    15. 1.15. suspend(), resume(), stop()
    16. 1.16. join()
    17. 1.17. yield()
  2. 2. 쓰레드의 동기화(synchronization)
    1. 2.1. synchronized를 이용한 동기화
    2. 2.2. wait()와 notify()