Java 기반 클라우드 융합 개발자 과정 - KH 정보교육원/5월

22. 05. 04 - Thread, 생성하기-사용하기

giggs 2022. 5. 12. 16:31

 

Thread - 

 

 

  • 쓰레드는 일꾼이다.
  • 쓰레드는 하는 일이 정해져 있어야 한다 run() 메서드로!
  • run() 메서드는 우리가 만드는 메서드가 아니다.
  • run() 메서드는 누가 만들어 놓은 메서드를 다시 사용하는 것이다.
  • @Override run( ) 해서 지정해 주어야 한다~!
  • 쓰레드를 만드려고 하면 run() 메서드를 가진 부모가 일단 있어야 한다.
  • 이 부모의 형태가 2가지이다. 클래스이거나 인터페이스이거나
  • 클래스는 extends /  인터페이스는 implements 해주어야 한다.

 

 

 


 

 

 

쓰레드 생성방식 3가지

  • extends 
  • implements
  • lambda

 

 

 

 

 

쓰레드 생성 방법이 왜 종류가 여러 개 인가요?

  • java는 단일 상속만 가능하므로
  • IF ) 이미 Person 상속받은 Man을 Thread 로 만들어 주려면?
  • 다중 상속 불가! implement만 가능

 

 

 

 

 

 

  • 보통 implements 많이 사용한다. extends로 박아놓으면 다른 부모 사용 못하니까.
  • 람다는 왜 나왔냐??
  • 간단하게 말하면 implemnets / extends 해서 하는 작업을 람다식으로 간단히 사용하기 위해서
  • 쓰레드 하나한테 출력문 하나 실행하는 일 시킬 건데 그거 하려고
  • 인터페이스 구현한 클래스 만들고 다시 쓰레드 만들고 하기 번거롭고 힘들다..

 

 

실습하면서 알아보자!

 

 

 


 

 

 

실습

  • 쓰레드 생성하기
  • 쓰레드 사용하기

 

 

쓰레드 생성하기 1번째 – extends Thread

 

 

 

1. extends Thread

  • Thread 클래스 안에 run() 메서드 있다.
  • 이제 MyThread를 실행하면 우리가 만들어 놓은 run() 실행된다.

 

 

extends Thread 하고 @Override run()

 

 

 


 

 

 

2. 메인에서 쓰레드 생성해주기 - new MyThread();

  • 메인에서 객체 생성 실행 테스트
  • 왜 run()이 아니라 - start(); 메서드로 사용하나요?
  • run()으로 사용해봤더니 둘 다 main메서드가 작업해준다.
  • start() 라는 것은 - 새로운 객체(쓰레드)를 만들어 주고-> run() 메서드를 실행해주는 의미
  • 메인 메서드 안에서 그냥 run() 해버리면 – 메인쓰레드한테 그냥 run()하라고 명령한 의미

 

 

run()이 아닌 start() 메서드로 호출한 것 Check !

 

 

 

 

 


 

 

 

 

+@ 메인 쓰레드의 역할

 

  • 메인쓰레드가 쭉 가면서 t1 쓰레드 생성해주고 다시 돌아와서 나머지 일 실행
  • --- 나의 이해
  • 메인 쓰레드가 객체를 생성하고 접근해서 메서드를 실행하고 돌아오고 하는 거였는데,
  • 쓰레드.start() 의 경우에는 메인 쓰레드가 객체를 찾아가서 그 안에 run()까지 실행하는 게 아니라
  • 객체(쓰레드)를 만들어 주기만 하고 돌아오고, 그 객체(쓰레드)가 알아서 run() 실행하게 놔두는 거라고 이해

 

 

객체에 대해서 새로운 정의

  • 객체 스스로 일을 한다. 이 객체가 이거 한다 이거 한다 이런 식으로 생각해왔다.
  • BUT 사실은 객체가 스스로 일을 하는 것이 아니다.
  • 객체도 보면 데이터 덩어리이다.( 데이터가 있고 메서드가 있는)

 

int x = new Hello().hello();

  • 객체를 생성하고 / 접근해서 / hello() 메서드 실행 / 변수 x에 담는다.
  • 여기서 접근해서! 이 부분!에
  • 쓰레드가! 일을 다 한다.
  • 접근해서 – 메서드 실행하고 그 값을 – 변수 x에 담아주는 일을 한다.
  • 객체가 한 일은? 데이터 제공?

 

 

MyQuestion -

  • 쓰레드는 시작만 해주면 자기 할 일 다 끝내면 종료는 자동으로 되는 건가요?
  • 작업이 끝나면 쓰레드가 없어지는 건가요?
  • -> 맞습니다, 쓰레드가 죽은 상태가 된다.
  • 쓰레드.isAlice(); 로 확인 가능 ( 너무 빠르게 확인하면 살아있다고 나올 수도 있다. )

 

 

 

 


 

  

 

 

쓰레드 생성하기 2번째 – implement Runnable

 

 

 

1. implement Runnable

  • implements Runnable – 추상 메서드 구현하라고 컴파일 에러 난다.
  • @Override run(){}

 

 

 

 

 

 


 

 

 

2. new MyThread(My Runner());

 

 

 

 

 

 

## Check Point 

  • 러너는 쓰레드 만든 것처럼 바로 사용할 수 없고.
  • 어떤 쓰레드를 생성해주고 –
  • 그 안쪽에 인자 값으로 러너를 전달하는 방식으로 사용

 

 

  • new Thread(); 만들면 – 비어있는 상태다. 
  • run()을 오버라이드 해줘야 하는데 == run() 메서드를 채워주어야 하는데
  • 현재 우리가 run() 오버라이드 한 방식은 – MyRunner()로 오버라이드 한 상태
  • MyRunner 객체로 전달 가능하다.
  • 가능한 이유는 MyRunner 는 - Runnable이라는 interface를 가지고 있기 때문에
  • ( Runnable을 구현한 클래스 객체는 가능하다 )
  • 함수 지향적 프로그램

 

 

 

 


 

 

 

 

+@ FunctionalInterface

 

  • Runnable 이란 인터페이스는 –> run() 이라는 메서드 단 하나만을 보유한 인터페이스
  • 이런 인터페이스를 Functional Interface 라고한다.!
  • Functional Method

 

 

 

 

 

나온 이유?

  • java는 타입 언어 / python, javascript 이런 애들은 논 타입 언어
  • 합의점을 찾는 방향으로 생태계 변화 중인데 그 역할
  • – 다른 언어의 장점을 사용할 수 있는 방법으로!
  • 함수형 프로그래밍 – 자바에서는 변수에 함수를 넣을 방법이 없었다.
  • 그런데 객체를 넣는 것은 가능하네?
  • 이 객체를 interface로 만들어서 하자.
  • 대신 이 interface는 메소드 1개만 가지도록 해주자. - 이것이 functional interface

 

 

 

 

 


 

 

 

 

 

쓰레드 생성하기 3번째 – 람다식

 

  • 변수에 함수를 넣어주기 위해선
  • implements Runnable해준 객체나 extends Thread해준  객체를  생성해서 넣어주어야 하는데
  • 이런 방법이 너무 번거롭고 힘들다.
  • 이 작업을 좀 더 쉽게 해 주기 위해 - 람다식이 나왔다.

 

 

위에서 했던 객체를 생성해서 넣어주는 작업은

메소드(입력값, 할 일, 출력 값) 하나를 채워주기 위한 것인데 너무 번거롭고 힘들다.

이런 작업을 편리하고, 수월하게 해주자 하는 것이 람다식 (입력값, 할 일, 출력 값)을 채워주는 것

 

 

 

 

 

1. new Thread(); 생성 - 

 

 

 

 

 

  • 이 상태는 현재 t3 쓰레드 안에는 비어있는 상태
  • run() 메서드를 채워주어야 한다.
  • 지금까지 extends / implements 해서 객체를 넣어 준 이유는?
  • run() 메서드를 채워 주기 위해서
  • 그럼 굳이 객체로 채워주지 말고 메서드를 넣어주자

 

 

 

 


 

 

 

 

2. 람다식으로 run() 메서드 채워주기

 

 

2-1 명령어가 1개일 때 : ()->()

 

중괄호 { } 와 세미클론 ; 없는 것 Check!

 

 

  • { } 생략 가능
  • ; 생략 가능

 

 


 

 

 

2-2 명령어가 2개일 때 : ()->{();}

 

 

 

 

  • { } 필요 
  • ; 필요 ( 명령어 하나하나마다 )

 

 

 

 

 


 

 

 

 

여기까지 쓰레드 생성하는 방법 3가지 알아봤고

쓰레드 사용하는 방법 중 start 하나 알아보았다.

 

 

 

쓰레드 사용하는 방법 더 알아보자!

 

 

 

쓰레드에서 알아야 할 키워드

[ start, run, sleep, interrupt, wait, notify, notifyAll, state, join, yield, daemon, group, pool, priority ]

 

 

 


 

 

start , run

  • 쓰레드.start() 하면 run()메서드 실행

 

 

sleep

  • 쓰레드 잠재움, 대기열로 일정 시간 동안 보낸 후 다시 실행하게 해 준다.

 

 

stop( xxx )

  • 쓰레드 종료 ( 이제 안씀 - flag로 흐름 제어 )
  • 쓰레드 자원 낭비와 비정상 종료 에러로 사용 안 하는 추세
  • isFlag = true || false 해서 무한 반복문 제어해준다.

 

 

interrupt

  • 쓰레드를 방해한다. 
  • 쓰레드가 예외 던지고 종료한다.
  • 사용 중에 방해를 받으면 그 즉시가 아니라, wait상태로 바뀌는 순간 - 예외처리로 던져버리고 종료
  • 한 사이클 동작하고 그만했으면 좋겠다는 상황에서 주로 사용

 

 

wait

  • sleep이랑 비슷
  • wait() 메서드를 만나면 대기 상태로 간다.
  • 몇 초 동안 대기 상태로 보내는 초 지정도 가능.( 다만 sleep()와 달리 그 시간을 다 채우지 않아도 누가 깨워주면 다시 가서 수행 )
  • 동기화 관련 차이가 있음( 모니터 획득, lock 여부 등)

 

 

notify, notifyAll

  • 깨우다 - 대기실에 wait 하는 애들 다시 일하라고 명령함
  • 대기 상태에 있는 어떤 쓰레드를 깨워주는 역할을 한다.
  • 객체 안에는 대기열이 있다.
  • 쓰레드가 객체에 와서 작업을 하다가 메서드 안에서 wait()을 만나게 됐다?
  • 이 메서드를 대기열로 보낸다. t1 대기열로
  • 이상태에서 t2가 와서 notify() 하게 되면 대기열에 있는 쓰레드 중 하나 깨워준다(어떤것일지는 모른다)
  • 그래서 notifyAll로 대기실에 있는 모든 애들 한 번에 깨워줄 수도 있다.

 

 

state

  • 쓰레드의 상태( 생성 , 실행 , 대기 , 종료 )

 

 

join

  • 다른 쓰레드 기다려 줌
  • t2의 결과 값이 필요한 경우에 사용

 

 

yield

  • 다른 쓰레드한테 컴퓨터 자원 cpu 쓸 수 있게 양보하다.
  • core가 1개다? thread 1개밖에 못돌림.( 실제로는 아니지만 예시로 )
  • S/W 잘 깔아봤자 H/W가 못 받쳐주면 일 못함.
  • 예시) Thread 100개가 있다. / 코어가 16개 있다.
  • 1번부터 16번 쓰레드까지는 할 일을 하는데 나머지는 일을 못한다.
  • 그럴 때 다른 쓰레드가 1번 쓰레드한테 양보하라고 yield하면 쓰던 코어 반납하고 내려놓는다.
  • 양보해봤자 우선순위가 낮은 애한테는 양보 안됨. 꼭 그렇지도 않음..
  • 요즘은 yield() 사용 잘 안 함. 내가 원하는 대로 통제하기도 어려움

 

 

daemon

  • 다른 쓰레드에 종속되는 쓰레드
  • 부노 쓰레드가 종료되면 데몬 쓰레드도 종료
  • 처음부터 데몬쓰레드로 만들어 주어야 함
  • 예시) ctrl + z , ctrl + y 이런거 사용하는데 // 이런 기능들은 메인 기능들이 아니다.
  • 이런 부가적인 기능을 수행하는 쓰레드 t1은 main쓰레드가 있어야 존재할 수 있다.
  • main 없는데 ctrl + z , ctrl + y 기능? 필요 없다. 존재할 이유 없다.
  • 이럴 상황일 때 처음부터 daemon 쓰레드로 만들어 준다.

 

 

group

  • 쓰레드를 그룹단위로 묶어서 관리하는

 

 

pool

  • 쓰레드를 매번 만들어서 사용하고 하는 것이 아니라.
  • 만들어 놓고 가져다 사용하는

 

 

priority

  • 쓰레드 우선순위 지정 ( 우선순위대로 실행 안 되는 경우도 많다 )

 

 

 

 


 

 

 

 

진도 +

 

 

 

 

 

최근 트렌드는 병렬 프로그래밍을 좋아하는 추세

  • H/W의 발전에 따라서 - H/W가 받쳐줘서 – 동시에 많은 쓰레드를 사용 가능해져서
  • 병렬 프로그램 사용 안 하면 손해다. / core가 100개가 있는데 10개만 사용하면 자원 손해.
  • 이런 병렬 프로그래밍 작업이 어려운데 – 함수로 만들어놨다. 
  • 함수만 호출하면 병렬 프로그램으로 만들어줌 – 이거와 연관되어있는 것이 – 함수형 프로그래밍
  • 요즘은 함수형 프로그래밍이 인기~!

 

 

 

 

 

 

 

 

교착상태

  • dead lock -사거리 한가운데 교통사고... 사거리 뒤에 차들 다 막혀있는 상태

기아 상태

  • cpu 자원을 못 먹는 상태 – 검색해보자~

 

 

cpu가 쓰레드들에게 자원을 주는데

그 스케줄을 cpu스케줄러가 조정 고려해야 함

t1, t2중 항상 t1이 먼저 시작 안될 수도 있음

 

 

 

 

 

  • sync 싱크로나이즈 – 동기화

 

 

 

 

 

 

 

 

  • 중간에 줄 그어지는 메서드들 - Deprecated 메서드
  • 버전 업그레이드되면 사라질 수도 있는 애들

 

 


 

 

 



review


Thread
쓰레드를 생성하는 3가지 방법!
사용하는 여러 가지 방법!

쓰레드는 한 가지 일만 하는 것인지 알게 되었고,
만드는 방법 3가지의 특징과 만드는 상황을 알 수 있었다.

오버 라이딩은 run() 메서드
실행은 start() 메서드로 하는 부분도 새로웠다.

이론적으로만 배웠던 프로세스의 상태
[ 생성 - 준비 - 실행 - 대기 ]를
sleep(), wait(), notify() 등
여러 가지 사용방법을 실습해 보면서 이해할 수 있어서 좋았다.


이제 쓰레드를 생성하고 사용하는 기초를 배웠으니
쓰레드를 활용해서 프로그래밍하는 연습을 더 하면 될 듯.
화이팅!!ㅎㅎ