Skip to content

Latest commit

Β 

History

History
419 lines (287 loc) Β· 20.1 KB

Thread.md

File metadata and controls

419 lines (287 loc) Β· 20.1 KB

Thread

Table of contents generated with markdown-toc

Thread

μ •μ˜

ThreadλŠ” CPUμ—μ„œ μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” κ°€μž₯ μž‘μ€ λ‹¨μœ„μ΄λ‹€. ν”„λ‘œκ·Έλž¨ ν•˜λ‚˜λ₯Ό μ‹€ν–‰μ‹œν‚€λ©΄ ν•˜λ‚˜ μ΄μƒμ˜ threadκ°€ μ‹€ν–‰λœλ‹€. 예λ₯Όλ“€μ–΄, "Hello, World"λΌλŠ” μžλ°” ν”„λ‘œκ·Έλž¨μ„ μ‹€ν–‰μ‹œν‚€λ©΄ λ¬Έμžμ—΄μ„ 좜λ ₯ν•˜λŠ” μ“°λ ˆλ“œκ°€ μ‹€ν–‰λœλ‹€. ν•˜μ§€λ§Œ μ‹€μ œλ‘œλŠ” λ‹€λ₯Έ μ“°λ ˆλ“œλ„ 같이 싀행이 λ˜λŠ”λ°, λ©”λͺ¨λ¦¬ μž‘μ—…μ„ ν•΄μ£ΌλŠ” GC(Garbage Collection) κ΄€λ ¨ μ“°λ ˆλ“œκ°€ κ·Έ μ˜ˆμ΄λ‹€.

μ™œ μ‚¬μš©ν• κΉŒ?

두 가지 연산을 μˆ˜ν–‰ν•˜λŠ” 상황이 μžˆλ‹€κ³  κ°€μ •ν•˜μž. ν•˜λ‚˜λŠ” 1λΆ€ν„° 1000κΉŒμ§€μ˜ 합을 κ΅¬ν•˜λŠ” 연산이고, λ‹€λ₯Έ ν•˜λ‚˜λŠ” 1λΆ€ν„° 10κΉŒμ§€μ˜ 곱을 κ΅¬ν•˜λŠ” 연산이닀.

public class EX1 {
    public static void main(String[] args) {
        int calculation1 = 1;
        int calculation2 = 1;

        for(int i=2;i<=1000;i++) calculation1+=i;
        for(int i=2;i<=10;i++) calculation2*=i;

        System.out.println("calculation1 is " + calculation1);
        System.out.println("calculation2 is " + calculation2);
    }
}

ν”„λ‘œκ·Έλž¨ μ‹€ν–‰ 과정은 μš°μ„  calculation1을 계산 ν›„, calculation2λ₯Ό κ³„μ‚°ν•œλ‹€.

ν•˜μ§€λ§Œ μ—°μ‚° 1κ³Ό μ—°μ‚° 2λŠ” 독립적인데, 아무 관계가 μ—†λŠ” 두 연산을 ꡳ이 μˆœμ„œλŒ€λ‘œ ν•  μ΄μœ κ°€ μ—†λ‹€. 즉 두 연산을 ν•œκΊΌλ²ˆμ— 해도 상관이 μ—†λ‹€.

μ“°λ ˆλ“œλ₯Ό 톡해 두 연산을 λ™μ‹œμ— μ§„ν–‰ν•΄λ³΄μž.

class C1 extends Thread{
    public void run() {
        int result = 1;
        for(int i=2;i<=1000;i++) result+=i;
        System.out.println("calculation1 is " + result);
    }
}

class C2 extends Thread{
    public void run() {
        int result = 1;
        for(int i=2;i<=10;i++) result*=i;
        System.out.println("calculation2 is " + result);
    }
}

class ex2 {
    public static void main(String[] args) {
        C1 c1 = new C1();
        C2 c2 = new C2();

        c1.start();
        c2.start();
    }
}

좜λ ₯κ²°κ³Ό

calculation2 is 3628800
calculation1 is 500500

c1κ³Ό c2의 연산이 λ™μ‹œμ— μ‹€ν–‰ λ˜λŠ”λ°, c2λŠ” 10번만 연산을 μˆ˜ν–‰ν•˜λ―€λ‘œ 더 빨리 λλ‚˜κΈ° λ•Œλ¬Έμ— 좜λ ₯κ²°κ³ΌλŠ” c2κ°€ λ¨Όμ €λ‚˜μ™”λ‹€.

λ§Œμ•½ 두 개의 연산이 1μ‹œκ°„μ”© κ±Έλ¦°λ‹€λ©΄, μ“°λ ˆλ“œλ₯Ό μ•ˆμ“΄λ‹€λ©΄ 각각 연산을 μˆ˜ν–‰ν•΄μ•Ό ν•˜λ―€λ‘œ 2μ‹œκ°„μ΄ κ±Έλ¦¬κ² μ§€λ§Œ, μ“°λ ˆλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ 연산을 λ™μ‹œμ— μˆ˜ν–‰ν•˜λ―€λ‘œ 1μ‹œκ°„μ΄ 걸릴것이닀.

μƒνƒœ

https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=http%3A%2F%2Fcfile27.uf.tistory.com%2Fimage%2F99D9E94B5A3CAD770ADF38

https://sjh836.tistory.com/121

NEW

μ“°λ ˆλ“œκ°€ μƒμ„±λœ μƒνƒœ. 아직 start() λ˜μ§€ μ•ŠμŒ

RUNNABLE

start()κ°€ ν˜ΈμΆœλ˜μ–΄ μ‹€ν–‰ λŒ€κΈ°. run() ν•˜λ©΄ Running(CPU 점유)이 λœλ‹€. Runnable pool에 λͺ¨μ—¬μžˆμŒ

WAITING

μΌμ‹œμ •μ§€, λ‹€λ₯Έ μ“°λ ˆλ“œμ˜ 톡지λ₯Ό κΈ°λ‹€λ¦Ό

TIMED_WAITING

μΌμ‹œμ •μ§€, 주어진 μ‹œκ°„λ™μ•ˆ κΈ°λ‹€λ¦Ό

BLOCK

μΌμ‹œμ •μ§€, μ‚¬μš©ν•˜λ €λŠ” 객체의 lock이 풀릴 λ•Œ κΉŒμ§€ λŒ€κΈ° etc..

TERMINATED

μ‹€ν–‰ 마친 λ’€ μ’…λ£Œ. run()이 λλ‚˜λ©΄ terminated λ˜λ©΄μ„œ μ†Œλ©Έ

μŠ€μΌ€μ€„λ§

μžλ°” μ“°λ ˆλ“œλŠ” μš°μ„ μˆœμœ„λž‘ λΌμš΄λ“œλ‘œλΉˆμœΌλ‘œ μŠ€μΌ€μ€„λ§ν•œλ‹€.

μš°μ„ μˆœμœ„

Priority 값이 높은 μ“°λ ˆλ“œκ°€ μ‹€ν–‰ μƒνƒœλ₯Ό 더 많이 가진닀. 기본이 5이며 κ°œλ°œμžκ°€ setPriority()λ₯Ό 톡해 컨트둀 ν•  수 μžˆλ‹€.

λΌμš΄λ“œ 둜빈

μ‹œκ°„ ν• λ‹ΉλŸ‰(Time Slice)λ₯Ό μ •ν•˜μ—¬ ν•˜λ‚˜μ˜ μ“°λ ˆλ“œλ₯Ό 정해진 μ‹œκ°„λ§ŒνΌ μ‹€ν–‰μ‹œν‚¨ λ’€ λ‹€λ₯Έ μ“°λ ˆλ“œλ₯Ό μ‹€ν–‰ν•œλ‹€. JVM이 μ»¨νŠΈλ‘€ν•œλ‹€.

Thread ν΄λž˜μŠ€μ™€ Runnable μΈν„°νŽ˜μ΄μŠ€

μ“°λ ˆλ“œλ₯Ό μƒμ„±ν•˜λŠ” 방법은 두 가지가 μžˆλŠ”λ°, ν•˜λ‚˜λŠ” Thread 클래슀λ₯Ό μ‚¬μš©ν•˜λŠ” 것이고, λ‹€λ₯Έ ν•˜λ‚˜λŠ” Runnable μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν•˜λŠ” 것이닀.

두 클래슀 λͺ¨λ‘ java.lang νŒ¨ν‚€μ§€μ— μžˆμœΌλ―€λ‘œ λ³„λ„μ˜ importκ°€ ν•„μš”μ—†λ‹€. λ˜ν•œ Runnable μΈν„°νŽ˜μ΄μŠ€μ—λŠ” κ΅¬ν˜„ν•  λ©”μ†Œλ“œκ°€ run()만 μ‘΄μž¬ν•˜λ―€λ‘œ, run()만 κ΅¬ν˜„ν•˜λ©΄ λœλ‹€.

class UseRunnable implements Runnable {

    @Override
    public void run() {
        System.out.println("UseRunnable run() method.");
    }
}

class UseThread extends Thread {
    public void run() {
        System.out.println("UseThread run() method.");
    }
}

class ThreadSample {
    public static void main(String[] args) {
        UseRunnable useRunnable = new UseRunnable();
        UseThread useThread = new UseThread();

        new Thread(useRunnable).start();
        useThread.start();

        System.out.println("ThreadSample program ends");
    }
}

μ‹€μ œλ‘œ μ‹€ν–‰λ˜λŠ” 뢀뢄은 run() λ©”μ†Œλ“œμ΄κ³ , κ·Έ 뢀뢄을 μ‹€ν–‰μ‹œν‚€λŠ” λ©”μ†Œλ“œλŠ” start()이닀. μ“°λ ˆλ“œλ₯Ό μƒμ„±ν–ˆλ‹€κ³  ν•΄μ„œ μžλ™μœΌλ‘œ μ‹€ν–‰λ˜λŠ” 것이 μ•„λ‹ˆλΌ, start()λ₯Ό ν˜ΈμΆœν•΄μ•Ό μ“°λ ˆλ“œκ°€ μ‹€ν–‰λœλ‹€. μ‹€μ œλ‘œλŠ” start()κ°€ 호좜 λ˜μ–΄μ„œ λ°”λ‘œ μ‹€ν–‰λ˜λŠ” 것이 μ•„λ‹ˆλΌ, μ‹€ν–‰ λŒ€κΈ° μƒνƒœμ— μžˆλ‹€κ°€ μžμ‹ μ˜ μ°¨λ‘€κ°€ λ˜μ–΄μ•Ό μ‹€ν–‰λœλ‹€. μ‹€ν–‰ λŒ€κΈ° 쀑인 μ“°λ ˆλ“œκ°€ μ—†λ‹€λ©΄ λ°”λ‘œ μ‹€ν–‰μƒνƒœκ°€ λœλ‹€.

ν•˜μ§€λ§Œ Runnable을 κ΅¬ν˜„ν•˜μ—¬ λ§Œλ“  μ“°λ ˆλ“œλŠ” λ°”λ‘œ μ‹€ν–‰ν•  수 μ—†κ³ , new Thread(useRunnable)κ³Ό 같이 Thread 클래슀의 μƒμ„±μžλ₯Ό 톡해 객체λ₯Ό λ§Œλ“€μ–΄μ•Ό ν•œλ‹€.

λ²ˆκ±°λ‘­μ§€λ§Œ μžλ°”μ—μ„œλŠ” 닀쀑상속이 λ˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ—, Thread 클래슀λ₯Ό 상속 λ°›λŠ”λ‹€λ©΄ λ‹€λ₯Έ ν΄λž˜μŠ€λŠ” 상속받을 수 μ—†λ‹€. ν•˜μ§€λ§Œ μΈν„°νŽ˜μ΄μŠ€λŠ” μ—¬λŸ¬ 개λ₯Ό κ΅¬ν˜„ν•  수 μžˆμœΌλ―€λ‘œ 보톡은 Runnable을 κ΅¬ν˜„ν•˜λŠ” 것이 μΌλ°˜μ μ΄λ‹€.

ν•œ 번 μ’…λ£Œλœ μ“°λ ˆλ“œλŠ” λ‹€μ‹œ μ‹€ν–‰ν•  수 μ—†λ‹€. 즉, ν•˜λ‚˜μ˜ μ“°λ ˆλ“œμ— λŒ€ν•΄ start()κ°€ ν•œ 번만 호좜될 수 μžˆλ‹€. 만일 μ“°λ ˆλ“œμ˜ μž‘μ—…μ„ ν•œ 번 더 μˆ˜ν–‰ν•΄μ•Ό ν•œλ‹€λ©΄, μƒˆλ‘œμš΄ μ“°λ ˆλ“œλ₯Ό μƒμ„±ν•œ λ‹€μŒ start()λ₯Ό ν˜ΈμΆœν•΄μ•Όν•œλ‹€. ν•˜λ‚˜μ˜ μ“°λ ˆλ“œμ— λŒ€ν•΄ start()λ₯Ό 두 번 이상 ν˜ΈμΆœν•˜λ©΄ μ‹€ν–‰ μ‹œμ— IllegatThreadStateException이 λ°œμƒν•œλ‹€.

μœ„μ˜ μ½”λ“œλ₯Ό μ—¬λŸ¬ 번 μ‹€ν–‰μ‹œν‚€λ©΄, 좜λ ₯μˆœμ„œκ°€ 뒀죽박죽이 λœλ‹€. μ“°λ ˆλ“œλ₯Ό start() λ©”μ†Œλ“œλ₯Ό 톡해 μ‹œμž‘ν–ˆλ‹€λŠ” 것은, ν•˜λ‚˜μ˜ μ“°λ ˆλ“œλ₯Ό JVM에 μΆ”κ°€ν•˜μ—¬ μ‹€ν–‰ν•œλ‹€λŠ” 것이닀. new Thread(useRunnable).start()λ₯Ό 톡해 useRunnable μ“°λ ˆλ“œκ°€ JVM에 μΆ”κ°€λ˜κ³ , useThread.start()λ₯Ό 톡해 useTread μ“°λ ˆλ“œκ°€ JVM에 μΆ”κ°€λœλ‹€. useRunnable이 useThreadλ₯Ό 톡해 JVM에 λ“€μ–΄κ°”μ§€λ§Œ λ―Έμ„Έν•œ 차이이며 두 μ“°λ ˆλ“œκ°€ ν•¨κ»˜ μ‹€ν–‰λ˜κ³  같은 연산을 해도 CPU μƒνƒœμ— 따라 μ‹€ν–‰μ‹œκ°„μ— λ―Έμ„Έν•œ 차이가 μžˆμ„ 수 μžˆλ‹€.

λ˜ν•œ useRunnableκ³Ό useThreadλŠ” ThreadSample ν”„λ‘œκ·Έλž¨κ³Ό λ³„κ°œλ‘œ μ§„ν–‰λ˜λ―€λ‘œ, useRunnable, useThreadλŠ” μ§„ν–‰μ€‘μ΄λ©΄μ„œ κ·Έ λ°‘μ˜ 좜λ ₯ μ½”λ“œκ°€ μ‹€ν–‰λœλ‹€. λ”°λΌμ„œ κ²°κ³Όκ°€ 뒀죽박죽이 λœλ‹€.

yield()

μš°μ„ κΆŒμ΄ λ™μΌν•œ μ“°λ ˆλ“œμ—κ²Œ μ‹€ν–‰ν•  기회λ₯Ό μ–‘λ³΄ν•œλ‹€. 이λ₯Ό μ‹€ν–‰ν•˜λ©΄ RUNNING μƒνƒœμ—μ„œ RUNNABLE μƒνƒœλ‘œ 바뀐닀.

sleep()

일정 μ‹œκ°„ λ™μ•ˆ μ“°λ ˆλ“œλ₯Ό λ©ˆμΆ”κ²Œ ν•œλ‹€.

static void sleep(long millis);
static void sleep(long millis, int nanos);

밀리 μ„Έμ»¨λ“œ(1000λΆ„μ˜ 1초)와 λ‚˜λ…Έ μ„Έμ»¨λ“œ(10μ–΅λΆ„μ˜ 1초)의 μ‹œκ°„ λ‹¨μœ„λ‘œ μ„Έλ°€ν•˜κ²Œ 값을 지정할 수 μžˆλ‹€.

sleep을 ν˜ΈμΆœν•  땐 항상 try-catch문으둜 μ˜ˆμ™Έ 처리λ₯Ό ν•΄μ•Όν•œλ‹€.

join()

λ‹€λ₯Έ μ“°λ ˆλ“œμ™€ ν˜‘λ™ μž‘μ—…ν•  λ•Œ 주둜 μ“΄λ‹€. 호좜되면 BLOCKED μƒνƒœκ°€ λ˜μ—ˆλ‹€κ°€, κΈ°λ‹€λ¦¬λŠ” μ“°λ ˆλ“œμ˜ μž‘μ—…μ΄ λλ‚˜λ©΄ λ‹€μ‹œ RUNNABLE둜 κ°„λ‹€.

main μ“°λ ˆλ“œ

데λͺ¬ μ“°λ ˆλ“œ(daemon thread)

main λ©”μ†Œλ“œμ˜ μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” 것도 μ“°λ ˆλ“œμ΄λ©°, 이λ₯Ό main μ“°λ ˆλ“œλΌκ³  ν•œλ‹€. μ§€κΈˆκΉŒμ§€λŠ” main λ©”μ†Œλ“œκ°€ μˆ˜ν–‰μ„ 마치면 ν”„λ‘œκ·Έλž¨μ΄ μ’…λ£Œλ˜μ—ˆμ§€λ§Œ main λ©”μ†Œλ“œκ°€ μˆ˜ν–‰μ„ λ§ˆμ³€λ‹€κ³  ν•˜λ”λΌλ„ λ‹€λ₯Έ μ“°λ ˆλ“œκ°€ 아직 μž‘μ—…μ„ λ§ˆμΉ˜μ§€ μ•Šμ€ μƒνƒœλΌλ©΄ ν”„λ‘œκ·Έλž¨μ΄ μ’…λ£Œλ˜μ§€ μ•ŠλŠ”λ‹€.

synchronized

ν•˜λ‚˜μ˜ μ“°λ ˆλ“œκ°€ μž‘μ—…μ„ λ‹€ 끝내기 μ „μ—λŠ” λ‹€λ₯Έ threadκ°€ μž‘μ—…μ˜ μ œμ–΄κΆŒμ„ 가져가지 λͺ»ν•˜κ²Œ ν•œλ‹€.

  • ThreadλŠ” 곡유 μžμ›μ„ μ„œλ‘œ sharing ν•œλ‹€.
  • λ‚΄κ°€ μž‘μ—…ν•˜λŠ” λ™μ•ˆ μ–΄λ–€ μ“°λ ˆλ“œλ„ λ°©ν•΄ν•˜μ§€ λͺ»ν•˜λ„둝 보μž₯받아야함
  • 동기화 μ²˜λ¦¬λŠ” 무겁기 λ•Œλ¬Έμ— ν•΄λ‹Ήν•˜λŠ” κΈ°λŠ₯μ—λ§Œ μ²˜λ¦¬ν•΄μ•Όν•œλ‹€.
public class CommonCalculate {
    private int value;

    public CommonCalculate(){
        value = 0;
    }

    public void plus(){
        value++;
    }

    public int getValue(){
        return value;
    }
}

value값을 λ”ν•΄μ£ΌλŠ” ν΄λž˜μŠ€μ΄λ‹€.

public class ChangeValue extends Thread{
    private CommonCalculate calc;

    public ChangeValue(CommonCalculate calc){
        this.calc = calc;
    }

    public void run(){
        for(int i=0; i<10000; i++) calc.plus();
    }
}

CommonCalculateλ₯Ό λ‹€λ£¨λŠ” ChangeValueλΌλŠ” ν΄λž˜μŠ€μ΄λ‹€. calc의 value값을 1μ”© μ¦κ°€μ‹œν‚€λŠ” μž‘μ—…μ„ 만 번 μˆ˜ν–‰ν•œλ‹€.

그리고 이 두 클래슀λ₯Ό μ‚¬μš©ν•˜λŠ” SyncEx 클래슀λ₯Ό λ§Œλ“ λ‹€.

public class SyncEx {
    public static void main(String[] ar){
        CommonCalculate calc = new CommonCalculate();
        ChangeValue t1 = new ChangeValue(calc);
        ChangeValue t2 = new ChangeValue(calc);

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

        try{
            t1.join();
            t2.join();
            System.out.println("calc.value = " + calc.getValue());
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

calc 객체λ₯Ό t1κ³Ό t2 λͺ¨λ‘ μ‚¬μš©ν•œλ‹€. 그리고 t1, t2κ°€ μ‹€ν–‰λ˜λŠ”λ°, try-catch문에 μžˆλŠ” join λ©”μ†Œλ“œλŠ” ν•΄λ‹Ή μ“°λ ˆλ“œκ°€ 끝날 λ•Œ κΉŒμ§€ κΈ°λ‹€λ¦°λ‹€. 즉 t1, t2 μ“°λ ˆλ“œκ°€ λͺ¨λ‘ 끝날 λ•Œ κΉŒμ§€ κΈ°λ‹€λ Έλ‹€κ°€ calc 객체의 value 값을 ν™•μΈν•œλ‹€.

ν•˜μ§€λ§Œ 맀번 μ‹€ν–‰ν•  λ•Œ λ§ˆλ‹€ 값이 λ‹€λ₯Ό λΏλ”λŸ¬ μ˜ˆμƒκ°’κ³ΌλŠ” λ‹€λ₯΄κ²Œ λ‚˜μ˜€λŠ”λ°, κ·Έ μ΄μœ λŠ” t1κ³Ό t2 두 객체가 λ™μ‹œμ— μ§„ν–‰λ˜λ©΄μ„œ 같은 객체값을 가지고 μ—°μ‚°ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€.

plus() λ©”μ†Œλ“œμ˜ μ—°μ‚° μˆ˜ν–‰ 과정은 λ‹€μŒκ³Ό κ°™λ‹€.

1. ν˜„μž¬ value 값을 읽고
2. value++λ₯Ό κ³„μ‚°ν•˜κ³ 
3. value값에 value++ν•œ 값을 λŒ€μž…ν•˜λŠ” 것이닀.

value 값이 5라고 κ°€μ •ν•˜μž. t1의 μ“°λ ˆλ“œ 연산이 1단계λ₯Ό μ§€λ‚˜ 2단계 κΉŒμ§€ μˆ˜ν–‰ν•˜μ˜€λ‹€λ©΄, 남은 일은 λŒ€μž… 뿐이닀. ν•˜μ§€λ§Œ 이 λ•Œ t2 μ“°λ ˆλ“œκ°€ 1단계인 ν˜„μž¬ value값을 μ½λŠ” 단계λ₯Ό μ§„ν–‰ν•˜λ € ν•œλ‹€λ©΄, t2κ°€ 읽은 valueλŠ” 5κ°€ λ§žλ‹€. ν•˜μ§€λ§Œ t2κ°€ value값을 읽은 ν›„ t1이 3단계λ₯Ό μ§„ν–‰ν•˜λ©΄ valueλŠ” 6이 λœλ‹€. κ·Έλ ‡λ‹€λ©΄ t2κ°€ 3단계 κΉŒμ§€ μ§„ν–‰ν•œ λ‹€μŒμ˜ value값은 6이 될 것이닀. t1의 싀행이 λλ‚œ λ’€ t2κ°€ μ‹€ν–‰λ˜μ—ˆλ‹€λ©΄ value값은 7이 λ˜μ—ˆμ„ 것이닀.

이런 κ²½μš°λ“€μ„ 싱크가 μ•ˆλ§žκ±°λ‚˜ ν˜Ήμ€ μ“°λ ˆλ“œμ— μ•ˆμ „ν•˜μ§€ μ•Šλ‹€λΌκ³  ν‘œν˜„ν•˜λŠ”λ°, μ΄λŸ¬ν•œ 상황을 synchronized μ˜ˆμ•…μ–΄λ‘œ 방지할 수 μžˆλ‹€.

public synchronized void plus(){
        value++;
    }

plus() λ©”μ†Œλ“œμ— λ‹€μŒκ³Ό 같이 synchronized μ˜ˆμ•½μ–΄λ₯Ό 써주면 μ˜ˆμƒκ°’μ΄ λ‚˜μ˜¨λ‹€. synchronized λŠ” ν•΄λ‹Ή λ©”μ†Œλ“œκ°€ ν•˜λ‚˜μ˜ μ“°λ ˆλ“œμ—μ„œλ§Œ ν˜ΈμΆœλ˜λ„λ‘ ν•œλ‹€.

ν•˜μ§€λ§Œ μ΄λ ‡κ²Œ synchronizedλ₯Ό μ‚¬μš©ν•˜λ©΄ λΉ„νš¨μœ¨μ˜ λ¬Έμ œκ°€ λ°œμƒν•˜λŠ”λ°, 예λ₯Ό λ“€μ–΄ μ—¬λŸ¬ 개의 연산이 μ‘΄μž¬ν•˜κ³  싱크λ₯Ό κ³ λ €ν•΄μ•Όν•  연산은 ν•˜λ‚˜ 뿐이라고 κ°€μ •ν•˜μž. μ΄λŸ¬ν•œ μƒν™©μ—μ„œ λ©”μ†Œλ“œ μžμ²΄μ— synchronized λ₯Ό 뢙이면, λ©”μ†Œλ“œ μ•ˆμ˜ λͺ¨λ“  연산이 ν•œ λ²ˆμ— ν•˜λ‚˜μ˜ μ“°λ ˆλ“œ 만 μ ‘κ·Όν•  수 μžˆμœΌλ―€λ‘œ λΉ„νš¨μšΈμ μ΄λ‹€. 그런 경우 λ‹€μŒκ³Ό 같이 싱크λ₯Ό κ³ λ €ν•΄μ£Όκ³  싢은 μ—°μ‚°μ—λ§Œ synchronized λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.

Object plusLock = new Object();
public void plus(){
    synchronized(plusLock){
        value++;
    }
}

잠금 처리λ₯Ό ν•˜κΈ° μœ„ν•΄ this의 μ‚¬μš© λŒ€μ‹  λ³„λ„μ˜ 객체λ₯Ό μ‚¬μš©ν•˜μ—¬ lock ν•œλ‹€.

λ°λ“œλ½

λ©€ν‹° μ“°λ ˆλ“œλž€

1개의 μ‘μš©ν”„λ‘œκ·Έλž¨μ΄ μ“°λ ˆλ“œλ‘œ λΆˆλ¦¬λŠ” 흐름 처리 λ‹¨μœ„λ₯Ό 볡수 μƒμ„±ν•˜μ—¬ 볡수의 처리λ₯Ό λ³‘ν–‰ν•˜λŠ” 것이닀. 쀑앙 처리 μž₯치의 처리 μ‹œκ°„μ„ 맀우 짧은 λ‹¨μœ„λ‘œ λΆ„ν• ν•˜μ—¬ 볡수의 μ“°λ ˆλ“œμ— μ°¨λ‘€λ‘œ ν• λ‹Ήν•¨μœΌλ‘œμ¨ 볡수의 μ²˜λ¦¬κ°€ λ™μ‹œμ— μ΄λ£¨μ–΄μ§€λŠ” 것 처럼 보인닀.

문제점

  • λ™μ‹œμ— 볡수 개의 μ½”λ“œκ°€ 같은 μ£Όμ†Œ κ³΅κ°„μ—μ„œ μ‹€ν–‰λ˜λ―€λ‘œμ„œ μ„œλ‘œ κ°„μ„­ν•˜κ³  영ν–₯을 μ£Όλ©°, μ£Όμ†Œ 곡간 λΆ„λ¦¬μ˜ 이점이 μ—†λ‹€.
  • μ“°λ ˆλ“œκ°„μ˜ μ‹€ν–‰ μˆœμ„œλ₯Ό μ˜ˆμΈ‘ν•  수 μ—†μ–΄ 디버깅이 μ–΄λ ΅λ‹€.
  • 곡유 μžμ›μ„ λ³΄ν˜Έν•˜κΈ° μ–΄λ ΅λ‹€.

크리티컬 μ„Ήμ…˜

  • λ©€ν‹° μ“°λ ˆλ“œλŠ” μ“°λ ˆλ“œκ°„μ— μ‹€ν–‰ μˆœμ„œκ°€ κ·œμΉ™μ μ΄μ§€ μ•Šμ•„ 동기화λ₯Ό ν•΄μ£Όμ–΄μ•Ό ν•œλ‹€.
  • ν”„λ‘œμ„ΈμŠ€ λ‚΄μ—μ„œλ§Œ μ‚¬μš©ν•΄μ•Όν•˜λŠ” μ œμ•½μ΄ 있으며, μž„κ³„κ΅¬μ—­ ν˜Ήμ€ 치λͺ…적 μ˜μ—­μ΄λΌκ³  ν•œλ‹€.
  • λ‹€λ₯Έ μ“°λ ˆλ“œμ— μ˜ν•΄ 방해받지 말아야 ν•  μž‘μ—…μ„ ν•  λ•Œ, 이 μ˜μ—­μ„ 크리티컬 μ„Ήμ…˜μœΌλ‘œ λ‘˜λŸ¬μ‹Έλ©΄ μ „μ—­μžμ›μ˜ λ…μ κΆŒμ΄ μ£Όμ›Œμ§„λ‹€.

λ°λ“œλ½, 즉 ꡐ착 μƒνƒœλŠ” λ©€ν‹° μ“°λ ˆλ“œ 쀑 μ“°λ ˆλ“œ 간에 λŒ€κΈ° μƒνƒœκ°€ μ’…λ£Œλ˜μ§€ μ•Šμ•„ λ¬΄ν•œμ • λŒ€κΈ°λ§Œ ν•˜λŠ” 비정상적인 상황이닀. κΈ°μ•„(Starvation)μ™€λŠ” λ‹€λ₯΄κ²Œ 외뢀적 쑰치 μ—†μ΄λŠ” λ²—μ–΄λ‚  수 μ—†λ‹€.

원인

4가지 원인 쀑 ν•˜λ‚˜λΌλ„ λΆ€μ •κ°€λŠ₯ν•˜λ‹€λ©΄ ꡐ착 μƒνƒœμ— 빠지지 μ•ŠλŠ”λ‹€.

μžμ›μ˜ 배타적 μ‚¬μš©(Mutual Exclusion Condition)

배타적 μ‚¬μš©μ΄ μš”κ΅¬λ˜λŠ” μžμ›μ΄ 있으면 ꡐ착 μƒνƒœκ°€ λ°œμƒν•  수 μžˆλ‹€.

μžμ›μ˜ λΆ€λΆ„ ν• λ‹Ή(Partial Allocation, Hold and Wait)

ν”„λ‘œμ„ΈμŠ€λŠ” ν•„μš”ν•œ μ‹œμ μ— ν•„μš”ν•œ μžμ›μ„ λΆ€λΆ„μ μœΌλ‘œ ν™•λ³΄ν•˜κΈ°μ— μ–΄λŠ μ‹œμ μ— ν•„μš”ν•œ μžμ›μ„ 할당받지 λͺ»ν•˜μ§€λ§Œ ν™•λ³΄ν•œ μžμ›μ€ λ†“μΉ˜ μ•Šκ²Œ λ˜μ–΄ ꡐ착 μƒνƒœκ°€ λ°œμƒν•  수 μžˆλ‹€.

μžμ›μ˜ 선점 λΆˆκ°€λŠ₯μ„±(Non Preemption)

μžμ›μ΄ 선점 λΆˆκ°€ν•  경우 ꡐ착 μƒνƒœκ°€ λ°œμƒν•  수 μžˆλ‹€.

μžμ›μ— λŒ€ν•œ ν™˜ν˜• λŒ€κΈ°(Circular Wait)

μžμ›μ„ λ³΄μœ ν•œ μ±„λ‘œ μ„œλ‘œμ˜ μžμ›μ„ μš”μ²­ν•˜κ²Œλ˜λ©΄ ꡐ착 μƒνƒœκ°€ λ°œμƒν•  수 μžˆλ‹€.

ν•΄κ²°

예방(Prevention)

  • ꡐ착 μƒνƒœμ˜ 원인이 λ˜λŠ” 쑰건 쀑 ν•˜λ‚˜λ₯Ό μ—†μ•°μœΌλ‘œμ¨ ꡐ착 μƒνƒœ λ°œμƒμ„ λ°©μ§€ν•˜λŠ” 방법, ꡐ착 μƒνƒœλ₯Ό ν™•μ‹€νžˆ μ œκ±°ν•  수 μžˆμ§€λ§Œ μ‹¬κ°ν•œ μžμ› 낭비와 νŠΉμ • ν”„λ‘œμ„ΈμŠ€μ˜ λ¬΄ν•œ λŒ€κΈ° κ°€λŠ₯성이 μžˆλ‹€.
  • μžμ›μ˜ 배타적 μ‚¬μš©μ„ λ°°μ œλ°°νƒ€μ  μ‚¬μš©μ΄ ν•„μš”ν•œ μžμ›μ„ κ³΅μœ ν•  경우 큰 문제λ₯Ό μ•ΌκΈ°ν•  수 μžˆλ‹€. λ”°λΌμ„œ λ°°μ œν•  수 μ—†λ‹€.
  • μžμ›μ˜ 뢀뢄할당을 λ°°μ œμžμ‹ μ΄ ν•„μš”ν•œ λͺ¨λ“  μžμ›μ„ 미리 ν• λ‹Ήλ°›μ•„ μ‹€ν–‰ν•˜κ²Œλ” ν•˜λŠ” λ°©λ²•μœΌλ‘œ μ‹¬κ°ν•œ μžμ› λ‚­λΉ„λ₯Ό μ΄ˆλž˜ν•˜κ³  λ¬΄ν•œ λŒ€κΈ°μ— 빠질 수 μžˆλ‹€.
  • μžμ›μ˜ 선점 λΆˆκ°€λŠ₯성을 배제λͺ¨λ“  μžμ›μ΄ 선점 κ°€λŠ₯ν•  경우 비정상적인 ν”„λ‘œμ„ΈμŠ€ μ’…λ£Œλ‘œ μΈν•œ μžμ› 낭비와 λ¬΄ν•œ λŒ€κΈ°μ— 빠질 수 μžˆλ‹€.
  • μžμ›μ˜ ν™˜ν˜• λŒ€κΈ° 상황을 λ°°μ œμžμ›μ— λŒ€ν•œ μš°μ„  μˆœμœ„λ₯Ό μ±…μ •ν•˜μ—¬ ν”„λ‘œμ„ΈμŠ€κ°€ 이 μš°μ„ μˆœμœ„λ₯Ό μ§€μΌœ μš”μ²­ν•˜λ„λ‘ ν•˜λŠ” 방법, λ§ˆμ°¬κ°€μ§€λ‘œ μžμ›μ˜ 낭비와 λ¬΄ν•œ λŒ€κΈ°λ₯Ό κ²ͺ을 수 μžˆλ‹€.

νšŒν”Ό(Avoidance)

  • νŠΉμ •ν•œ μ•Œκ³ λ¦¬μ¦˜μ„ 톡해 μ‹œμŠ€ν…œμ˜ μƒνƒœκ°€ μ§€μ†μ μœΌλ‘œ μ•ˆμ „ μƒνƒœλ₯Ό μœ μ§€ν•  수 μžˆλ„λ‘ μ‘°μ ˆν•˜λŠ” 방법, μ•ˆμ „ μƒνƒœλŠ” ꡐ착 μƒνƒœκ°€ λ°œμƒν•  수 μ—†λŠ” μƒνƒœλ₯Ό μ˜λ―Έν•œλ‹€. λŒ€κΈ° μƒνƒœκ°€ κΈΈμ–΄μ§ˆ 수 μžˆμ§€λ§ŒΒ μ˜ˆλ°©λ³΄λ‹€ μžμ›μ˜ λ‚­λΉ„λ₯Ό κ°μ†Œμ‹œν‚¬ 수 μžˆλ‹€.
  • 은행가 μ•Œκ³ λ¦¬μ¦˜
    • 은행가 μ•Œκ³ λ¦¬μ¦˜μ΄ μ •μƒμ μœΌλ‘œ μž‘λ™ν•˜κΈ° μœ„ν•΄μ„œλŠ” λ‹€μŒκ³Ό 같은 μ „μ œκ°€ ν•„μš”ν•˜λ‹€.

      • μ‹œμŠ€ν…œ λ‚΄μ˜ ν”„λ‘œμ„ΈμŠ€ μˆ˜κ°€ κ³ μ •λ˜μ–΄ μžˆμ–΄μ•Ό ν•œλ‹€.
      • μžμ›μ˜ μˆ˜κ°€ κ³ μ •λ˜μ–΄ μžˆμ–΄μ•Ό ν•œλ‹€.
      • 각 ν”„λ‘œμ„ΈμŠ€κ°€ μš”κ΅¬ν•  μžμ›μ˜ μ΅œλŒ€ 개수λ₯Ό μ•Œμ•„μ•Ό ν•œλ‹€.
      • 각 ν”„λ‘œμ„ΈμŠ€λŠ” 할당받은 μžμ›μ„ μ‚¬μš©ν•œ ν›„ λ°˜λ“œμ‹œ λ°˜λ‚©ν•΄μ•Ό ν•œλ‹€.

      ν”„λ‘œμ„ΈμŠ€μ˜ μžμ› μš”μ²­μ΄ μžˆμ„ λ•Œ λ§ˆλ‹€ μš”μ²­μ— λ”°λ₯Έ 할당이 μ•ˆμ „ μƒνƒœλ₯Ό μœ μ§€ν•  수 μžˆλŠ”μ§€ ν™•μΈν•œλ‹€.Β μ•ˆμ „ μƒνƒœμ˜ νŒλ‹¨μ€ ν˜„ μƒνƒœμ—μ„œ λͺ¨λ“  ν”„λ‘œμ„ΈμŠ€κ°€ μ •μƒμ μœΌλ‘œ μ’…λ£Œν•  수 μžˆλŠ” 길이 적어도 ν•˜λ‚˜ 이상 μžˆλŠ” 것이닀.

탐지(Detection)

  • ꡐ착 μƒνƒœκ°€ λ°œμƒν•˜μ˜€μ„ λ•Œ κ·Έλ₯Ό νƒμ§€ν•˜μ—¬ 쑰치(볡ꡬ)λ₯Ό μ·¨ν•˜λŠ” 방법이닀. 탐지λ₯Ό μœ„ν•΄μ„œλŠ” ν˜„ μ‹œμŠ€ν…œμ˜ 상황을 μ•Œμ•„μ•Όν•˜λŠ”λ° μžμ› ν• λ‹Ή κ·Έλž˜ν”„(Resource Allocation Graph, RAG)둜 λ‚˜νƒ€λ‚Έλ‹€.
  • κ·Έλž˜ν”„ μ œκ±°λ²•
    • 싱크(λ‚˜κ°€λŠ” 간선이 μ—†λŠ” ν”„λ‘œμ„ΈμŠ€ λ…Έλ“œ, ν™œλ™μ΄ κ°€λŠ₯ν•œ ν”„λ‘œμ„ΈμŠ€)λ‘œλΆ€ν„° μ‹œμž‘ν•˜μ—¬ λ“€μ–΄μ˜€λŠ” λͺ¨λ“  간선을 μ œκ±°ν•œλ‹€.(가지고 있던 μžμ›μ˜ λ°˜λ‚©) λͺ¨λ“  싱크에 λŒ€ν•΄μ„œ 같은 μž‘μ—…μ„ μˆ˜ν–‰ν–ˆμ„ λ•Œ 간선이 λ‚¨μ•„μžˆμœΌλ©΄ ꡐ착 μƒνƒœλ‹€.
  • κ·Έλž˜ν”„ 탐색법
    • λŒ€κΈ° 상황을 λ‚˜νƒ€λ‚΄λŠ” 간선을 따라 μ§„ν–‰ν–ˆμ„ λ•Œ 싱크가 발견되면 ꡐ착 μƒνƒœκ°€ μ—†μœΌλ©° λͺ¨λ“  경둜λ₯Ό 탐색해도 싱크가 λ°œκ²¬λ˜μ§€ μ•ŠλŠ”λ‹€λ©΄ ꡐ착 μƒνƒœκ°€ μžˆλŠ” 것이닀.사이클은 λͺ¨λ“  μžμ›μ΄ ν•œ κ°œμ”© μžˆμ„ λ•Œλ§Œ ꡐ착 μƒνƒœλ₯Ό λ‚˜νƒ€λ‚Έλ‹€.

볡ꡬ(Recovery)

  • **ν”„λ‘œμ„ΈμŠ€μ˜ μ’…λ£Œ(Process Termination)**νŠΉμ • ν”„λ‘œμ„ΈμŠ€λ₯Ό μ’…λ£Œμ‹œμΌœ μžμ›μ„ ν™•λ³΄ν•˜λŠ” λ°©λ²•μœΌλ‘œ ν”„λ‘œμ„ΈμŠ€λ₯Ό μ’…λ£Œμ‹œν‚¬ λ•Œ μ’…λ£Œ λΉ„μš©μ„ μ΅œμ†Œν™”ν•˜λŠ” 것이 관건이닀.

    • μ’…λ£Œ λΉ„μš©μ΄ κ°€μž₯ μ €λ ΄ν•œ ν•˜λ‚˜μ˜ ν”„λ‘œμ„ΈμŠ€λ₯Ό μ’…λ£Œμ‹œν‚€λŠ” λ°©λ²•ν•˜λ‚˜λ₯Ό μ’…λ£Œμ‹œν‚¬ λ•Œ λ§ˆλ‹€ ꡐ착 μƒνƒœκ°€ μ œκ±°λ˜μ—ˆλŠ”μ§€ ν™•μΈν•΄μ•Όν•œλ‹€.
    • λͺ¨λ“  λΆ€λΆ„ 집합을 λ§Œλ“€μ–΄ μ’…λ£Œ λΉ„μš©μ΄ κ°€μž₯ μ €λ ΄ν•œ ν•˜λ‚˜μ˜ λΆ€λΆ„ 집합을 λͺ¨λ‘ μ’…λ£Œμ‹œν‚€λŠ” 방법λͺ¨λ“  λΆ€λΆ„ 집합에 λŒ€ν•œ λΉ„μš©μ„ κ³„μ‚°ν•˜κΈ°κ°€ λ³΅μž‘ν•˜κ³  νž˜λ“€λ‹€.
  • μžμ›μ˜ 선점에 μ˜ν•œ 방식

    μžμ›μ„ μ„ μ μ‹œμΌœ ꡐ착 μƒνƒœλ₯Ό ν•΄μ†Œν•˜λŠ” λ°©λ²•μœΌλ‘œ μ„ μ μœΌλ‘œ μΈν•œ 볡ꡬ λΉ„μš©μ„ μ΅œμ†Œν™”ν•˜λŠ” 것이 관건이닀.

    • 검사점 지정(Checkpointing)ν”„λ‘œμ„ΈμŠ€μ˜ μ‹€ν–‰ 쀑간 쀑간에 결과값을 μ €μž₯해두어 λ³΅κ΅¬μ‹œ κ²€μ‚¬μ μœΌλ‘œ 볡ꡬ
  • 좜처

    https://onsil-thegreenhouse.github.io/programming/java/2018/05/23/java_tutorial_1-25/

    https://velog.io/@ednadev/4.-μžλ°”-μ“°λ ˆλ“œ-Thread-ydh851la

    https://velog.io/@hyeon930/운영체제-5.-ꡐ착-μƒνƒœDeadlock

    https://velog.io/@godkimchichi/Java-6-Thread-State

    https://sjh836.tistory.com/121