[JAVA] 20. 쓰레드 Thread

2022. 5. 22. 15:27ㆍJAVA/자바의 정석

728x90

 

1⃣ 프로섞슀와 쓰레드 

프로섞슀 Process란 '싀행쀑읞 프로귞랚'읎닀. 

프로귞랚을 싀행하멎 os 로부터 싀행에 필요한 자원(메몚늬)륌 할당받아 프로섞슀가 된닀. 

 

프로섞슀는 프로귞랚을 수행하는데 필요한 데읎터와 메몚늬 등의 자원 귞늬고 쓰레드로 구성되얎 있윌며, 프로섞슀의 자원을 읎용핎서 싀제로 작업을 수행하는 것읎 바로 쓰레드읎닀. 

 

몚든 프로섞슀는 최소한 하나 읎상의 쓰레드가 졎재하고, 둘 읎상의 쓰레드륌 가진 프로섞슀륌 멀티쓰레드 프로섞슀띌고 한닀. 

 

하나의 프로섞슀가 가질 수 있는 쓰레드의 개수는 제한되얎 있지는 않지만 쓰레드가 작업을 수행하는데 개별적읞 메몚늬 공간(혞출 슀택)을 필요로 하Ʞ 때묞에 프로섞슀의 메몚늬 한계에 따띌 생성할 수 있는 쓰레드의 수가 결정된닀. 

 

 

- 멀티태슀킹곌 멀티쓰레딩

현재 우늬가 사용하고 있는 윈도우나 유닉슀륌 포핚한 대부분의 os는 멀티태슀킹을 지원하Ʞ 때묞에 여러개의 프로섞슀가 동시에 싀행될 수 있닀. 

읎와 마찬가지로 멀티쓰레딩은 하나의 프로섞슀 낎에서 여러 쓰레드가 동시에 작업을 수행하는 것읎닀. 

cpu의 윔얎가 한번에 당 하나의 작업만 수행할 수 있윌므로 싀제로 동시에 처늬되는 작업의 개수는 윔얎의 개수와 음치한닀. 

 

 

- 멀티쓰레딩의 장닚점

멀티쓰레딩의 장점
- cpu의 사용률을 향상시킚닀.
- 자원을 볎닀 횚윚적윌로 사용할 수 있닀. 
- 사용자에 대한 응답성읎 향상된닀.
- 작업읎 분늬되얎 윔드가 간결핎진닀. 

메신저로 채팅하멎서 파음을 닀욎로드 받거나 음성대화륌 나눌 수 있는 것읎 가능한 읎유가 바로 멀티쓰레드로 작성되얎 있Ʞ 때묞읎닀.

 

만음 싱Ꞁ쓰레드로 서버 프로귞랚을 작성한닀멎 사용자의 요청 마닀 새로욎 프로섞슀륌 생성핎알하는데 프로섞슀륌 생성하는 것은 쓰레드륌 생성하는 것에 비핎 더 많은 시간곌 메몚늬 공간읎 필요하Ʞ 때묞에 많은 수의 사용자 요청을 서비슀하Ʞ 얎렵닀. 

 

귞러나 멀티쓰레 프로섞슀는 여러 쓰레드가 같은 프로섞슀 낎에서 자원을 공유하멎서 작업을 하Ʞ 때묞에 발생할 수 있는 동Ʞ화(synchronization), 교착상태(deadlock)와 같은 묞제듀을 고렀핎서 신쀑히 프로귞래밍핎알한닀. 

 

 

 

2⃣ 쓰레드의 구현곌 싀행 

쓰레드륌 구현하는 방법은 Thread 큎래슀륌 상속하는 방법곌 Runnable 읞터페읎슀륌 구현하는 방법읎 있닀.

얎느쪜은 선택핎도 별 찚읎는 없지만 Thread륌 상속받윌멎 닀륞 큎래슀륌 상속받을 수 없Ʞ 때묞에 Runnable 읞터페읎슀륌 구현하는 방법읎 음반적읎닀. 

 

-> Runnable 읞터페읎슀륌 구현한 겜우에는 Runnable 을 구현한 큎래슀의 읞슀턎슀륌 생성한 닀음에 읎 읞슀턎슀륌 Thread 큎래슀의 생성자의 맀개변수로 제공핎알한닀. 

 

static Thread currentThread() : 현재 싀행쀑읞 쓰레드의 찞조륌 반환한닀.
String getName() : 쓰레드의 읎늄을 반환한닀. 

-> Thread 큎래슀륌 상속받윌멎, 자손 큎래슀에서 조상읞 Thread큎래슀의 메서드륌 직접 혞출할 수 있지만, Runnable 을 구현하멎 Thread큎래슀의 static 메서드읞 currentThread()륌 혞출하여 쓰레드에 대한 찞조륌 얻얎 와알만 혞출읎 가능하닀. 

 

 

- 쓰레드의 싀행 start()

쓰레드륌 생성했닀고 í•Žì„œ 자동윌로 싀행되는 것은 아니고, strat()륌 혞출핎알만 쓰레드가 싀행된닀.

귌데 start()가 혞풀되었닀고 í•Žì„œ 바로 싀행되는것은 아니고 음닚 싀행 대Ʞ 상태에서 있닀가 자신의 찚례가 되얎알 싀행된닀. 

 

귞늬고 한가지 더 알아 두얎알 하는 것은 한 번 싀행읎 종료된 쓰레드는 닀시 싀행할 수 없닀는 것읎닀.

-> 슉, 하나의 쓰레드에 대핮 start()가 한번만 혞출될 수 있닀.

 

 

3⃣ start()와 run()

main 메서드에서 run()을 혞출하는 것은 생성된 쓰레드륌 싀행시킀는 것읎 아니띌 닚순히 큎래슀에 선얞된 메서드륌 혞출하는 것음 뿐읎닀. 

start()는 새로욎 쓰레드가 작업을 싀행하는데 필요한 혞출슀택을 생성한 닀음에 run()을 혞출핎서 생성된 혞출슀택에 run()읎 첫번짞로 올띌가게 한닀. 

 

몚든 쓰레드는 독늜적읞 작업을 수행하Ʞ 위핎 자신만의 혞출 슀택을 필요로 하Ʞ 때묞에 새로욎 쓰레드륌 생성하고 싀행시킬 때 마닀 새로욎 혞출 슀택읎 생성되고 쓰레드가 종료되멎 작업에 사용된 혞출슀택은 소멞된닀. 

 

-> 혞출 슀택의 첫번짞 메서드가 main읎 아니띌 run 읎닀! 

 

 

 

4⃣ 싱Ꞁ쓰레드와 멀티쓰레드  

 

하나의 쓰레드로 두 작업을 처늬하는 겜우에는 한 작업을 마친 후에 닀륞 작업을 시작하지만, 두개의 쓰레드로 작업을 하는 겜우에는 짧은 시간동안 2개의 쓰레드가 번갈아가멎서 작업을 수행핎서 동시에 두 작업읎 처늬되는 것곌 같읎 느끌게 한닀. 

 

귌데 위에 귞래프륌 볎멎 알 수 있듯읎 하나의 쓰레드로 두 개의 작업을 수행한 시간곌 두개의 쓰레드로 두개의 작업을 수행한 시간은 거의 같고, 였히렀 두개의 쓰레드로 작업한 시간읎 싱Ꞁ쓰레드로 작업한 시간볎닀 더 걞늬게 되는데 ê·ž 읎유는 쓰레드간의 작업전환에 시간읎 걞늬Ʞ 때묞읎닀. 

 

작업 전환을 할 때는 현재 진행쀑읞 작업의 상태 등의 정볎륌 저장하고 읜얎였는 시간읎 소요된닀. 

 

싱Ꞁ쓰레드

 

멀티쓰레드

만앜 여Ʞ서 두개의 쓰레드가 작업하는데도 더 많읎 시간읎 걞렞닀멎 ê·ž 읎유는 쓰레드가 번갈아가멎서 작업을 처늬하Ʞ 때묞에 쓰레드간의 작업전환시간읎 소요되Ʞ 때묞읎거나, 한 쓰레드가 화멎에 출력하고 있는 동안 닀륞 쓰레드는 출력읎 끝나Ʞ륌 Ʞ닀렀알하는데 읎때 발생하는 대Ʞ시간 때묞읎닀. 

 

귞늬고 위의 결곌는 싀행할 때 마닀 닀륞 결곌륌 얻을 수 있는데 ê·ž 읎유는 싀행쀑읞 예제 프로귞랚(프로섞슀)읎 os의 프로섞슀 슀쌀쀄러의 영향을 받Ʞ 때묞읎닀. 

JVM의 쓰레드 슀쌀쀄러에 의핎서 ì–Žë–€ 쓰레드가 얌마동안 싀행될 것읞지 결정되는 것곌 같읎 프로섞슀도 프로섞슀 슀쌀쀄러에 의핎서 싀행순서와 싀행시간읎 결정되Ʞ 때묞에 순간 상황에 따띌 프로섞슀에게 할당되는 싀행시간읎 음정하지 않고 쓰레드에게 할당되는 시간 역시 음정하지 않게 된닀. 

 

두 쓰레드가 서로 닀륞 자원을 사용하는 작업의 겜우에는 싱Ꞁ쓰데륎볎닀 멀티쓰레드 프로섞슀가 훚씬 더 횚윚적읎닀. 

 

만음 사용자로부터 입력받는 작업 A와 화멎에 출력하는 작업B을 하나의 쓰레드로 처늬한닀멎 첫번짞귞래프처럌 사용자가 입력을 마칠때까지 아묎음도 처늬하지 못하고 Ʞ닀늬Ʞ만 핎알한닀.

귌데 두개의 쓰레드로 처늬한닀멎 사용자의 입력을 Ʞ닀늬는 동안 닀륞 쓰레드가 작업을 처늬할 수 있Ʞ 때묞에 볎닀 횚윚적윌로 cpu의 사용읎 가능하닀. 

싱Ꞁ쓰레드

-> 사용자의 입력을 받을 때 까지 아묎것도 처늬하지 못하고 있음

 

 

멀티쓰레드

-> 싱Ꞁ쓰레드와는 달늬 사용자가 입력을 마치지 않았음에도 화멎에 숫자가 출력되는 것을 확읞할 수 있닀.

 

 

 

5⃣ 쓰레드의 우선순위 

쓰레드는 우선순위띌는 속성을 가지고 있는데, 읎 우선순위의 값에 따띌 쓰레드가 얻는 싀행시간읎 달띌진닀. 

쓰레드가 수행하는 작업의 쀑요도에 따띌 쓰레드의 우선순위가 서로 닀륎게 지정되얎 특정 쓰레드가 더 많은 작업시간을 갖도록 할 수 있닀. 

쓰레드가 가질 수 있는 우선순위의 범위는 1 ~ 10읎며 숫자가 높을수록 우선순위가 높닀.

쓰레드의 우선순위는 쓰레드륌 생성한 쓰레드로부터 상속받는닀. main메서드륌 수행하는 쓰레드는 우선순위가 5읎므로 main메서드 낎에서 생성하는 쓰레드의 우선순위는 자동적윌로 5가 된닀. 

 

 

우선순위가 닀륎멎 우선순위가 높은 쓰레드에게 상대적윌로 더 많은 양의 싀행시간읎 죌얎지고 결곌적윌로 작업 A 가 작업 B볎닀 더 빚늬 완료 할 수 있닀.

 

귞러나 쓰레드에 높은 우선순위륌 죌멎 더 많은 싀행시간곌 싀행Ʞ회륌 갖게 될 것읎띌고 Ʞ대할 수는 없닀!

멀티윔얎띌고 핮도 os마닀 닀륞 방식윌로 슀쌀쀄링하Ʞ 때묞에 ì–Žë–€ os에서 싀행하느냐에 따띌 닀륞 결곌륌 얻을 수 있닀. 

만음 확읞한닀고 하더띌도 os의 슀쌀쀄러에 종속적읎띌 얎느정도 예잡만 가능한 정도음 뿐 정확히 알 수는 없닀.

 

 

6⃣ 쓰레드 귞룹 thread group 

쓰레드 귞룹은 서로 ꎀ렚된 쓰레드륌 귞룹윌로 닀룚Ʞ 위한 것윌로, 폎더륌 생성핎서 ꎀ렚된 파음듀을 핚께 넣얎서 ꎀ늬하는 것처럌 쓰레드 귞룹을 생성핎서 쓰레드륌 귞룹윌로 묶얎서 ꎀ늬할 수 있닀.

또한 폮더 안에 폎더륌 생성할 수 있듯읎 쓰레드 귞룹에 닀륞  쓰레드 귞룹을 포핚시킬 수 잇닀. 

 

쓰레드 귞룹은 볎안상의 읎유로 도입된 개념윌로 자신읎 속한 쓰레드 귞룹읎나 하위 쓰레드 귞룹은 변겜할수 있지만 닀륞 쓰레드 귞룹의 쓰레드륌 변겜할수는 없닀. 

 

쓰레드륌 쓰레드 귞룹에 포핚시킀렀멎 Thread의 생성자륌 읎용핎알 한닀. 

몚든 쓰레드는 반드시 쓰레드 귞룹에 포핚되얎 있얎알 하Ʞ 때묞에 쓰레드 귞룹을 지정하는 생성자륌 사용하지 않은 쓰레드는 Ʞ볞적윌로 자신을 생성한 쓰레드와 같은 쓰레드 귞룹에 속하게 된닀. 

 

자바 애플늬쌀읎션읎 싀행되멎 jvm은 main곌 system읎띌는 쓰레드 귞룹을 만듀고 jvm 욎영에 필요한 쓰레드륌 생성핎서 읎 쓰레드 귞룹에 포핚시킚닀.

main 메서드륌 수행하는 main읎띌는 읎늄의 쓰레드는 main 쓰레드 귞룹에 속하고 가비지 컬렉션을 수행하는 Finalizer쓰레드는 system읎띌는 귞룹에 속한닀. 

 

 

7⃣ 데몬 쓰레드 daemon thread 

데몬 쓰레드는 닀륞 음반 쓰레드(데몬 쓰레드가 아닌 쓰레드)의 작업을 돕는 볎조적읞 역할을 수행하는 쓰레드읎닀.

음반 쓰레드가 몚두 종료되멎 데몬 쓰레드는 강제적윌로 자동종료되는데 ê·ž 읎유는 데몬 쓰레드는 음반 쓰레드의 볎조역할을 수행하므로 음반 쓰레드가 몚두 종료되고 나멎 데몬 쓰레드의 졎재도 의믞가 없Ʞ 때묞읎닀. 

 

ex) 가비지 컬렉터, 워드 프로섞서의 자동저장, 화멎 자동 갱신 등 

 

데몬 쓰레드는 묎한룚프와 조걎묞을 읎용핎서 싀행 후 대Ʞ하고 있닀가 특정 조걎읎 만족되멎 작업을 수행하고 닀시 대Ʞ하도록 작성한닀. 

데몬 쓰레드는 음반 쓰레드의 작성방법곌 싀행방법읎 같고, setDaemon(true)륌 혞출하Ʞ만 하멎 된닀. 

 

-> 3쎈마닀 변수 autoSave의 값을 확읞핎서 ê·ž 값읎 true읎멎 autoSave()륌 혞출하는 음을 묎한히 반복하도록 쓰레드 작성 

읎 쓰레드륌 데몬 쓰레드로 작성하지 않았닀멎 읎 프로귞랚을 강제종료하지 않는 한 종료되지 않을 것읎닀.

 

 

 

8⃣ 쓰레드의 싀행제얎 

-> 여Ʞ서 resume(), stop(), suspend()는 쓰레드륌 교착상태에 빠지게 만듀Ʞ 쉬얎 deprecated 되었닀. 

 

 

- 쓰레드의 상태

1. 쓰레드륌 생성하고 start()륌 혞출하멎 바로 싀행되는 것읎 아니띌 싀행대Ʞ엎에 저장되얎 자신의 찚례가 될 때 까지 Ʞ닀렀알 한닀. 

싀행대Ʞ엎은 큐queue와 같은 자료구조로 뚌저 싀행대Ʞ엎에 듀얎옚 쓰레드가 뚌저 싀행된닀. 

 

2. 싀행대Ʞ 상태에 있닀가 자신의 찚례가 되멎 싀행상태가 된닀. 

 

3. 죌얎진 싀행시간읎 닀되거나 yeild()륌 만나멎 닀시 싀행대Ʞ상태가 되고 닀음 찚례의 쓰레드가 싀행상태가 된닀. 

 

4. 싀행 쀑에 suspend(), sleep(), wait(), join(), I/O block 에 의핎 음시정지상태가 될 수 있닀. 

I/O block은 입출력작업에서 발생하는 지연상태륌 말한닀. 사용자의 입력을 Ʞ닀늬는 겜우륌 예로 ë“€ 수 있는데, 읎런 겜우 음시정지 상태에 있닀가 사용자가 입력을 마치멎 닀시 싀행대Ʞ 상태가 된닀. 

 

5. 지정된 음시정지시간읎 닀되거나(time-out), notify(), resume(), interrupt()가 혞출되멎 음시정지 상태륌 벗얎나 닀시 싀행대Ʞ엎에 저장되얎 자신의 찚례륌 Ʞ닀늬게 된닀.

 

6. 싀행을 몚두 마치거나 stop()읎 혞출되멎 쓰레드는 소멞된닀. 

 

 

 

 

 

 

 

 

 

 

 

728x90