πŸ“™ Java

[Java] μŠ€λ ˆλ“œ(Thread)

ji_wonna 2022. 9. 18. 00:26

μŠ€λ ˆλ“œλž€?

ν”„λ‘œμ„ΈμŠ€λŠ” μ‹€ν–‰ 쀑인 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ μ˜λ―Έν•˜λ©° ν”„λ‘œμ„ΈμŠ€ λ‚΄μ—μ„œ μ‹€ν–‰λ˜λŠ” μ†ŒμŠ€ μ½”λ“œμ˜ μ‹€ν–‰ 흐름을 μŠ€λ ˆλ“œλΌκ³  ν•œλ‹€. ν•˜λ‚˜μ˜ μŠ€λ ˆλ“œλ₯Ό κ°€μ§€λŠ” ν”„λ‘œμ„ΈμŠ€λ₯Ό μ‹±κΈ€ μŠ€λ ˆλ“œ ν”„λ‘œμ„ΈμŠ€, μ—¬λŸ¬ 개의 μŠ€λ ˆλ“œλ₯Ό κ°€μ§€λŠ” ν”„λ‘œμ„ΈμŠ€λ₯Ό λ©€ν‹° μŠ€λ ˆλ“œ ν”„λ‘œμ„ΈμŠ€λΌκ³  λΆ€λ₯Έλ‹€.

μžλ°”λ₯Ό μ‹€ν–‰ν•˜λ©΄ κ°€μž₯ λ¨Όμ € μ‹€ν–‰λ˜λŠ” λ©”μ„œλ“œλŠ” main이며, 메인 μŠ€λ ˆλ“œκ°€ main λ©”μ„œλ“œλ₯Ό μ‹€ν–‰μ‹œν‚¨λ‹€.

 

 

 

μŠ€λ ˆλ“œλ₯Ό μƒμ„±ν•˜λŠ” 2가지 방법

μŠ€λ ˆλ“œκ°€ μ‹€ν–‰ν•  μ½”λ“œλŠ” run() λ©”μ„œλ“œ 내에 μž‘μ„±ν•΄μ•Ό ν•˜λ©° run() λ©”μ„œλ“œλŠ” Runnable μΈν„°νŽ˜μ΄μŠ€(방법 1)와 Thread 클래슀(방법 2)에 μ •μ˜λ˜μ–΄ μžˆλ‹€.

 

방법 1. Runnable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ ν΄λž˜μŠ€μ—μ„œ run()을 κ΅¬ν˜„

Runnable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•  클래슀λ₯Ό μž‘μ„±ν•œ ν›„,

run()의 바디에 μŠ€λ ˆλ“œκ°€ μˆ˜ν–‰ν•  μ½”λ“œλ₯Ό μ λŠ”λ‹€.

λ§ˆμ§€λ§‰μœΌλ‘œ mainμ—μ„œ Runnable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ 객체λ₯Ό λ§Œλ“€κ³ , 이λ₯Ό Thread 클래슀 μƒμ„±μžμ˜ 인자둜 λ„˜κ²¨μ€˜μ„œ Thread 객체λ₯Ό λ§Œλ“€λ©΄ μŠ€λ ˆλ“œκ°€ μƒμ„±λœλ‹€.

μŠ€λ ˆλ“œλ₯Ό μƒμ„±ν•˜κ³  λ‚˜μ„œ start()λ₯Ό ν˜ΈμΆœν•˜λ©΄ μŠ€λ ˆλ“œκ°€ μ‹€ν–‰λœλ‹€.

public class ThreadEx {
    public static void main(String[] args) {
        Runnable task = new ThreadTask();
        Thread thread = new Thread(task);// μŠ€λ ˆλ“œ 생성
        thread.start();// μŠ€λ ˆλ“œ μ‹€ν–‰
    }
}

class ThreadTask implements Runnable {
    public void run() {// μŠ€λ ˆλ“œκ°€ μˆ˜ν–‰ν•  μž‘μ—…
        for (int i = 0; i < 100; i++) {
            System.out.print(i);
        }
    }
}

 

방법 2. Thread 클래슀λ₯Ό 상속받은 ν΄λž˜μŠ€μ—μ„œ run()을 κ΅¬ν˜„

Thread 클래슀λ₯Ό 상속 λ°›λŠ” 클래슀λ₯Ό μž‘μ„±ν•œλ‹€.

run()의 바디에 μŠ€λ ˆλ“œκ°€ μˆ˜ν–‰ν•  μž‘μ—…μ„ μž‘μ„±ν•œλ‹€.

start()둜 μŠ€λ ˆλ“œλ₯Ό μ‹€ν–‰μ‹œν‚¨λ‹€.

public class ThreadEx {
    public static void main(String[] args) {
        ThreadTask thread = new ThreadTask();// 생성
        thread.start();// μ‹€ν–‰
    }
}

class ThreadTask extends Thread {
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.print(i);
        }
    }
}

 

 

 

μŠ€λ ˆλ“œ 동기화

λ©€ν‹° μŠ€λ ˆλ“œ ν”„λ‘œμ„ΈμŠ€μ˜ 경우 ν•˜λ‚˜μ˜ μžμ›μ— μ—¬λŸ¬ 개의 μŠ€λ ˆλ“œκ°€ μ ‘κ·Όν•˜λ©΄ λ‹€μ–‘ν•œ λ¬Έμ œκ°€ 생길 수 μžˆλ‹€.

μ΄λŸ¬ν•œ λ¬Έμ œκ°€ λ°œμƒν•˜μ§€ μ•Šκ²Œ μˆ˜ν–‰ν•˜λŠ” μž‘μ—…μ„ μŠ€λ ˆλ“œ 동기화라고 ν•˜λ©° μžλ°”μ—μ„œλŠ” μž„κ³„ μ˜μ—­(Critical section) 지정과 락(Lock)을 톡해 동기화λ₯Ό μˆ˜ν–‰ν•œλ‹€.

μž„κ³„ μ˜μ—­μ€ ν•˜λ‚˜μ˜ μŠ€λ ˆλ“œλ§Œ μ ‘κ·Όν•  수 μžˆλŠ” μ½”λ“œ μ˜μ—­(μ—¬λŸ¬ 개의 μŠ€λ ˆλ“œκ°€ λ™μ‹œμ— μ ‘κ·Όν•˜λ©΄ μ•ˆ λ˜λŠ” μ˜μ—­)이며 synchronizedλ₯Ό μ‚¬μš©ν•˜μ—¬ μ„€μ •ν•œλ‹€. μž„κ³„ μ˜μ—­μ€ λ©”μ„œλ“œ 전체λ₯Ό 지정할 μˆ˜λ„ 있고 νŠΉμ • μ˜μ—­λ§Œ μ„€μ •ν•  μˆ˜λ„ μžˆλ‹€.

락은 μž„κ³„ μ˜μ—­μ„ ν¬ν•¨ν•˜κ³  μžˆλŠ” 객체에 μ ‘κ·Όν•  수 μžˆλŠ” κΆŒν•œμ„ μ˜λ―Έν•œλ‹€.

 

 

1. λ©”μ„œλ“œ 전체λ₯Ό μž„κ³„ μ˜μ—­μœΌλ‘œ μ§€μ •ν•˜κΈ°

λ©”μ„œλ“œμ˜ λ°˜ν™˜ νƒ€μž… 왼쑱에 synchronizedλ₯Ό μž‘μ„±ν•˜λ©΄ ν•΄λ‹Ή λ©”μ„œλ“œ 전체가 μž„κ³„ μ˜μ—­μœΌλ‘œ μ§€μ •λœλ‹€.

μ΄λ ‡κ²Œ 전체가 μž„κ³„ μ˜μ—­μΈ λ©”μ„œλ“œλŠ” ν˜ΈμΆœλ˜μ—ˆμ„ λ•Œ ν•΄λ‹Ή λ©”μ„œλ“œκ°€ ν¬ν•¨λœ 객체의 락을 μ–»μœΌλ©° μŠ€λ ˆλ“œκ°€ 락을 λ°˜λ‚©ν•˜κΈ° 전에 λ‹€λ₯Έ μŠ€λ ˆλ“œλŠ” λ©”μ„œλ“œμ— μ ‘κ·Όν•  수 μ—†λ‹€.

class SynchronizedEx {
    ...
    public synchronized boolean sync(int a) {
        ...
    }
}

 

2. νŠΉμ •ν•œ μ˜μ—­μ„ μž„κ³„ μ˜μ—­μœΌλ‘œ μ§€μ •ν•˜κΈ°

synchronized (<ν•΄λ‹Ή μ˜μ—­μ΄ ν¬ν•¨λœ 객체의 μ°Έμ‘°>) 둜 μž‘μ„±ν•˜κ³  {} μ•ˆμ— μ½”λ“œλ₯Ό μž‘μ„±ν•˜λ©΄ κ·Έ 뢀뢄이 μž„κ³„ μ˜μ—­μœΌλ‘œ μ§€μ •λœλ‹€.

class SynchronizedEx {
    ...
    public boolean sync(int a) {
            synchronized (this) {
               ...
            }
    }
}

 

 

 

μŠ€λ ˆλ“œμ˜ μƒνƒœμ™€ μ‹€ν–‰ μ œμ–΄ λ©”μ„œλ“œ

 

sleep(long milliSec): milliSec λ™μ•ˆ μŠ€λ ˆλ“œ μΌμ‹œ 정지

sleep()은 Thread의 클래슀 λ©”μ„œλ“œμ΄κΈ° λ•Œλ¬Έμ— 클래슀λ₯Ό 톡해 ν˜ΈμΆœν•˜λŠ” 것이 ꢌμž₯λœλ‹€.

sleep()을 ν˜ΈμΆœν•˜λ©΄ μŠ€λ ˆλ“œμ˜ μƒνƒœκ°€ μ‹€ν–‰μ—μ„œ μΌμ‹œ 정지 μƒνƒœλ‘œ μ „ν™˜λœλ‹€.

μΌμ‹œ 정지 μƒνƒœμ˜ μŠ€λ ˆλ“œλŠ” λ‹€μŒ 두 가지 κ²½μš°μ— μ‹€ν–‰ λŒ€κΈ° μƒνƒœλ‘œ λ³΅κ·€ν•œλ‹€.

  1. 인자둜 μ „λ‹¬ν•œ μ‹œκ°„λ§ŒνΌ μ‹œκ°„μ΄ μ§€λ‚œ 경우
  2. interrupt()λ₯Ό ν˜ΈμΆœν•œ 경우 (기본적으둜 μ˜ˆμ™Έκ°€ λ°œμƒν•˜κΈ° λ•Œλ¬Έμ— μ˜ˆμ™Έ 처리 ν•„μˆ˜)

 

 

interrupt(): μΌμ‹œ 정지 μƒνƒœμΈ μŠ€λ ˆλ“œλ₯Ό μ‹€ν–‰ λŒ€κΈ° μƒνƒœλ‘œ 볡귀

interrupt()λŠ” sleep(), wait(), join()에 μ˜ν•΄ μΌμ‹œ 정지 μƒνƒœμ— μžˆλŠ” μŠ€λ ˆλ“œλ“€μ„ μ‹€ν–‰ λŒ€κΈ° μƒνƒœλ‘œ λ³΅κ·€μ‹œν‚¨λ‹€.

λ§Œμ•½ μΌμ‹œ 정지 μƒνƒœκ°€ μ•„λ‹Œ μŠ€λ ˆλ“œμ—μ„œ interrupt()λ₯Ό ν˜ΈμΆœν•˜λ©΄ 기쑴에 ν˜ΈμΆœλ˜μ–΄ μŠ€λ ˆλ“œλ₯Ό λ©ˆμΆ”κ²Œ ν–ˆλ˜ sleep(), wait(), join()μ—μ„œ μ˜ˆμ™Έκ°€ λ°œμƒλ˜λ©° μΌμ‹œ 정지가 ν’€λ¦¬κ²Œ λœλ‹€.

 

 

yield(): λ‹€λ₯Έ μŠ€λ ˆλ“œμ—κ²Œ 싀행을 양보

반볡문의 μˆœνšŒκ°€ λΆˆν•„μš”ν•˜κ±°λ‚˜ λ¬΄μ˜λ―Έν•œ μž‘업을 μ‹€ν–‰μ‹œν‚¬ λ•Œ μœ μš©ν•˜κ²Œ μ‚¬μš©λœλ‹€.

yield()κ°€ 호좜되면 ν•΄λ‹Ή μŠ€λ ˆλ“œλŠ” μ‹€ν–‰ λŒ€κΈ° μƒνƒœλ‘œ λ°”λ€Œκ³  남은 μ‹€ν–‰ μ‹œκ°„μ„ μ‹€ν–‰ λŒ€κΈ°μ—΄μ—μ„œ μš°μ„ μˆœμœ„κ°€ 높은 μŠ€λ ˆλ“œμ—κ²Œ μ–‘λ³΄ν•œλ‹€.

 

 

join(long milliSec): λ‹€λ₯Έ μŠ€λ ˆλ“œμ˜ μž‘μ—…μ΄ 끝날 λ•ŒκΉŒμ§€ κΈ°λ‹€λ¦Ό

join()은 νŠΉμ • μŠ€λ ˆλ“œκ°€ μž‘μ—…ν•˜λŠ” λ™μ•ˆμ— μžμ‹ μ„ μΌμ‹œ 정지 μƒνƒœλ‘œ λ§Œλ“œλŠ” λ©”μ„œλ“œμ΄λ‹€.

sleep()κ³Ό λ§ˆμ°¬κ°€μ§€λ‘œ μ‹œκ°„μ΄ κ²½κ³Ό 됐을 λ•Œ, interrupt()κ°€ 호좜 됐을 λ•Œ μ‹€ν–‰ λŒ€κΈ° μƒνƒœλ‘œ λ³΅κ·€ν•˜κ³  join() 호좜 μ‹œ μ§€μ •ν–ˆλ˜ λ‹€λ₯Έ μŠ€λ ˆλ“œκ°€ μž‘μ—…μ„ λ§ˆμ³λ„ μ‹€ν–‰ λŒ€κΈ° μƒνƒœλ‘œ λ³΅κ·€ν•œλ‹€.

sleep()κ³Ό μœ μ‚¬ν•˜μ§€λ§Œ sleep()은 Thread 클래슀의 클래슀 λ©”μ„œλ“œ(static)이고 join()은 νŠΉμ • μŠ€λ ˆλ“œμ— λŒ€ν•΄ λ™μž‘ν•˜λŠ” μΈμŠ€ν„΄μŠ€ λ©”μ„œλ“œλΌλŠ” μ μ—μ„œ 차이λ₯Ό κ°–λŠ”λ‹€.

  • Thread.sleep(1000);
  • thread1.join();

 

 

wait(), notify(): μŠ€λ ˆλ“œ κ°„μ˜ ν˜‘μ—…μ— μ‚¬μš©

두 μŠ€λ ˆλ“œκ°€ κ΅λŒ€λ‘œ μž‘μ—…μ„ μ²˜λ¦¬ν•΄μ•Ό ν•  λ•Œ μœ μš©ν•œ μƒνƒœ μ œμ–΄ λ©”μ„œλ“œμ΄λ‹€.

A, B μŠ€λ ˆλ“œκ°€ ν˜‘μ—…ν•΄μ•Ό ν•  λ•Œ

Aκ°€ notify()λ₯Ό ν˜ΈμΆœν•˜λ©΄ Bκ°€ μ‹€ν–‰ λŒ€κΈ° μƒνƒœκ°€ 되고 AλŠ” wait()을 ν˜ΈμΆœν•˜λ©° μžμ‹ μ„ μΌμ‹œ 정지 μƒνƒœλ‘œ λ§Œλ“ λ‹€.

이런 과정이 λ°˜λ³΅λ˜λ©΄μ„œ 두 μŠ€λ ˆλ“œλŠ” 곡유 객체에 λ°°νƒ€μ μœΌλ‘œ μ ‘κ·Όν•˜λ©΄μ„œ 효과적으둜 ν˜‘μ—…ν•  수 μžˆλ‹€.