쓰레드
프로세스와 쓰레드
- 프로세스: 실행 중인 프로그램, 자원(resources)과 쓰레드로 구성
- 쓰레드: 프로세스 내에서 실제 작업을 수행
모든 프로세스는 최소한 하나의 쓰레드를 가지고있다. - 하나의 새로운 프로세스를 생성하는 거보다 하나의 새로운 쓰레드를 생성해주는 것이 더 적은 비용이 든다
- 단점
- 동기화
- 교착상태
- 기아(실행할기회없음)
쓰레드의 구현과 실행
- 자바는 단일 상속! 따라서 인터페이스 구현이 더.. 좋을수도
- 클래스 상속받기
- 인터페이스 구현
1 | class Ex13_1 { |
쓰레드의 실행 - start()
쓰레드를 생성한 후에 start()를 호출해야 쓰레드가 작업을 시작한다. 하지만 OS스케줄러가 실행 순서 결정하므로 순서 보장안됨. start()하자마자 바로 실행아님
t1.start()
t2.start()start()와 run()차이
결국 start()을 해야 새로운 호출스택을 생성후 run()을 돌린다
main쓰레드
- main메서드의 코드를 수행하는 쓰레드
- 쓰레드는 “사용자 쓰레드”와 “데몬 쓰레드” 두 종류가있다.
데몬 쓰레드==보조 쓰레드 - 실행 중인 사용자 쓰레드가 하나도 없을 때 프로그램은 종료된다.
- 즉, main 쓰레드가 종료되어도 run 쓰레드가 실행중이므로 프로그램 종료안됨!!
싱글쓰레드와 멀티쓰레드
- 그림과 다르게 멀티쓰레드는 OS스케줄러에 따라 길이가 다를수있음.
쓰레드의 I/O 블락킹(blocking)
- 외부장치의 입력 출력
쓰레드의 우선순위(priority of thread)
- 작업의 중요도에 따라 쓰레드의 우선순위를 다르게 하여 특정 쓰레드가 더 많은 작업시간을 갖게 할수 있다.
- setPriority(int ) (기본순위 5)
- getPriority( )
하지만 현실은 OS스케줄러에 반드시 희망사항대로 되지않는다.
1 | class Ex13_6 { |
쓰레드 그룹
- 서로 관련된 쓰레드를 그룹으로 묶어서 다루기 위한것
- 모든 쓰레드는 반드시 한의 쓰레드 그룹에 포함되어있어야한다
- 쓰레드 그룹을 지정하지 않고 생성한 쓰레드는 main쓰레드 그룹에 속한다
- 자신을 생성한 쓰레드(부모 쓰레드)의 그룹과 우선순위를 상속받는다
쓰레드 그룹의 메서드
데몬 쓰레드(daemon thread)
- 일반 쓰레드(non-daemon thread)의 작업을 돕는 보조적인 역할을 수행
- 일반 쓰레드가 모두 종료되면 자동적으로 종료된다
- 가비지 컬렉터, 자동저장, 화면 자동갱신 등에 사용된다.
- 무한루프와 조건문을 이용해서 실행 후 대기하다가 특정조건이 만족되면 작업을 수행하고 다시 대기하도록 작성한다.
- setDaemon()은 반드시 start()호출하기 전에 실행되어야한다.
1 | class Ex13_7 implements Runnable { |
쓰레드의 상태
쓰레드의 실행제어
- 쓰레드의 실행을 제어할 수 있는 메서드가 제공된다
- 이 들을 활용해서 보다 효율적인 프로그램의 작성할 수 있다.
- static 메서드는 자기 자신에게만 호출가능
Tread 실행제어 static 메서드
- sleep() 잠
- yield() 양보
(static) sleep()
- 현재 쓰레드를 지정한 시간동안 멈추게 한다. (this.sleep()임)
- 예외처리를 해야한다.(InterruptedException이 발생하면서 깨어남) (깨어나는것은 time up 또는 interrupted밖에없다)
- 특정 쓰레드를 지정해서 멈추게 하는 것은 불가능하다.
1 | class Ex13_8 { |
interrupt()
- 대기상태(WAITING)인 쓰레드를 실행대기 상태(RUNNABLE)로 만든다
- interrupt()는 해당 쓰레드클래스의 iv의 interrupted의 값을 변화시킴
- static interrupted()는 static이므로 지금 돌아가는 것의 interrupted여부를 확인하는것임!!!!!
suspend(), resume(), stop()
- 쓰레드의 실행을 일시정지, 재개, 완전정지 시킨다.
- 하지만 위의 함수보두 deprecated 이므로 권장 사용 안함!!
join()
- 지정된 시간동안 특정 쓰레드가 작업하는 것을 기다린다
- 예외처리를 해야한다.(InterruptedException이 발생하면 작업 재개)
yield()
- 남은 시간을 다음 쓰레드에게 양보하고, 자신(현재 쓰레드)은 실행대기한다.
- yield()와 interrupt()를 적절히 사용하면, 응답성과 효율을 높일 수있다. >> yield()는 OS스케줄러에게 의견제시하는거임(반드시X)
쓰레드의 동기화(synchronization)
- 멀티 쓰레드 프로세스에서는 다른 쓰레드의 작업에 영향을 미칠 수 있다.
- 진행중인 작업이 다른 쓰레드에게 간섭받지 않게 하려면 동기화 필요(한 쓰레드가 진행중인 작업을 다른 쓰레드가 간섭하지못하도록함)
- 동기화하려면 간섭받지 않아야하는 문장들을 “임계 영역”으로 설정
- 임계영역은 락(lock)을 얻은 단 하나의 쓰레드만 출입가능(객체 1개에 락 1개)
- 해당 객체와 관련된 곳은 모두 동기화해야함
synchronized를 이용한 동기화
synchronized로 임계여역(lock이 걸리는 영역)을 설정하는 방법2가지
예제
wait()와 notify()
- 동기화의 효율을 높이기 위해 wait(), notify()를 사용
- Object클래스에 정의되어 있으며, 동기화 블록 내에서만 사용할수있다.
- wait() - 객체의 lock을 풀고 쓰레드를 해당 객체의 waiting pool에 넣는다
- notify() - waiting pool에서 대기중인 쓰레드 중의 하나를 깨운다
- notifyAll() - waiting pool에서 대기중인 모든 쓰레드를 깨운다