λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
πŸ€ Java/μžλ°”μ™„μ „μ •λ³΅

[Java] μ“°λ ˆλ“œ 동기화, μ“°λ ˆλ“œ μƒνƒœ

by ._.sori 2025. 5. 26.

 

πŸ“š μ°Έκ³ ν•œ μ±…

 

: 좜처 예슀24 ν™ˆνŽ˜μ΄μ§€

 

 

 

- 기본적인 κ°œλ…μ„ μ •λ¦¬ν•˜κ³  μΆ”κ°€μ μœΌλ‘œ κΆκΈˆν•œ 것듀을 μ •λ¦¬ν–ˆμŠ΅λ‹ˆλ‹€ -

 

 

πŸ₯ πŸ₯ πŸ₯

 


 

βœ”οΈ   동기화_ 539p

 

• 동기화

: ν•˜λ‚˜μ˜ μž‘μ—…μ΄ μ™„λ£Œλœ ν›„ λ‹€λ₯Έ μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” 것

 

• 비동기화

: ν•˜λ‚˜μ˜ μž‘μ—… λͺ…λ Ή 이후 μ™„λ£Œ 여뢀와 상관없이 λ°”λ‘œ λ‹€λ₯Έ μž‘μ—… λͺ…령을 μˆ˜ν–‰ν•˜λŠ” 것

 

• λ©”μ„œλ“œ 동기화

: 2개의 μ“°λ ˆλ“œκ°€ λ™μ‹œμ— λ©”μ„œλ“œλ₯Ό μ‹€ν–‰ν•  수 μ—†λ‹€λŠ” 것

μ ‘κ·Όμ§€μ •μž synchronized λ¦¬ν„΄νƒ€μž… λ©”μ„œλ“œλͺ…(μž…λ ₯λ§€κ°œλ³€μˆ˜){ }
λ©”μ„œλ“œλ₯Ό 동기화할 λ•ŒλŠ” λ™κΈ°ν™”ν•˜κ³ μž ν•˜λŠ” λ©”μ„œλ“œμ˜ 리턴 νƒ€μž… μ•žμ— synchronized ν‚€μ›Œλ“œλ§Œ λ„£μœΌλ©΄ λœλ‹€. μ΄λ ‡κ²Œ 되면 λ™μ‹œμ— 2개의 μ“°λ ˆλ“œμ—μ„œ ν•΄λ‹Ή λ©”μ„œλ“œλ₯Ό μ‹€ν–‰ν•  수 μ—†κ²Œλœλ‹€. 

 

 

 

• 블둝 동기화

: 2개의 μ“°λ ˆλ“œκ°€ λ™μ‹œμ— ν•΄λ‹Ή 블둝을 μ‹€ν–‰ν•  수 μ—†λ‹€λŠ” 것

μ–΄λ–€ λ©”μ„œλ“œ {
    synchronized (μž„μ˜μ˜ 객체) { }
}
전체 λ©”μ„œλ“œλ₯Ό λ™κΈ°ν™”ν•˜μ§€ μ•Šκ³  μ›ν•˜λŠ” λΆ€λΆ„λ§Œ 동기화할 수 있게 ν•œλ‹€. ν•„μš”ν•œ μ½”λ“œλ§Œ 동기화λ₯Ό μ§„ν–‰ν•˜κΈ° λ•Œλ¬Έμ— λ©”μ„œλ“œ 동기화보닀 더 μ •λ°€ν•˜κ²Œ μ½”λ“œλ₯Ό μ„€μ •ν•  수 μžˆλ‹€. μ—¬κΈ°μ„œ μž„μ˜μ˜ κ°μ²΄λž€ λ‚΄κ°€ μ„ νƒν•œ μ–΄λ–€ 객체둜 μž κΈˆμ„ μ„€μ •ν•˜κ² λ‹€λŠ” 의미둜 μƒκ°ν•˜λ©΄ 되고 주둜 thisλ₯Ό μ‚¬μš©ν•΄μ„œ ν˜„μž¬ μΈμŠ€ν„΄μŠ€ 객체둜 μž κΈˆμ„ μ„€μ •ν•œλ‹€. 그러면 이 잠근 객체와 같은 객체λ₯Ό κ°€μ§€λŠ” 블둝듀은 λ™μ‹œ μ‚¬μš©μ΄ λΆˆκ°€ν•˜λ‹€.

 

 

 

• λ©”μ„œλ“œ 동기화와 블둝 동기화

class MyData {
    
    Object keyObject = new Object();
    synchronized void abc() {
    ...
    }
    
    synchronized void bcd() {
    ...
    }
    
    synchronized void cde() {
    ...
    }
    
    void def() {
        synchronized (keyObject) {
        ...
        }
    }
    
    void efg() {
        synchronized (keyObject) {
        ...
        }
    }
}
abc와 bcdλŠ” 동기화 λ©”μ„œλ“œμ΄λ‹€. cde와 def 그리고 efgλŠ” 동기화 블둝을 κ°€μ§€κ³  μžˆλ‹€. μ—¬κΈ°μ„œ 주의 깊게 봐야할 점은 μ–΄λ–€ λ©”μ„œλ“œκ°€ 동기화 λ©”μ„œλ“œμΈμ§€ 동기화 블둝인지가 μ•„λ‹ˆλ‹€. 각 λ©”μ„œλ“œμ™€ 블둝이 μ–΄λ–€ ν‚€λ‘œ 잠금이 λ˜μ–΄μžˆλŠ”μ§€λ₯Ό λ΄μ•Όν•œλ‹€. abc와 bcd 그리고 cdeλŠ” this 객체둜 잠금이 λ˜μ–΄μžˆλ‹€. 그러면 abc,bcd,cdeλŠ” λ™μ‹œμ— μ‚¬μš©ν•  수 μ—†λ‹€. def와 efgλŠ” keyObject둜 잠금이 λ˜μ–΄μžˆλ‹€. 그러면 def와 efgλŠ” λ™μ‹œμ— μ‚¬μš©ν•  수 μ—†λ‹€.

μ—¬κΈ°μ„œ 각 ν‚€λŠ” this와 keyObject둜 λ‚˜λ‰œλ‹€. ν‚€κ°€ λ‹€λ₯΄λ‹€λ©΄? λ™μ‹œμ— μ‚¬μš©κ°€λŠ₯ν•˜λ‹€. abcλŠ” cde와 λ™μ‹œμ— μ‚¬μš© λΆˆκ°€ν•˜μ§€λ§Œ abcκ°€ def와 λ™μ‹œ μ‚¬μš©μ€ κ°€λŠ₯ν•  것이닀. λ™κΈ°ν™”μ—μ„œ μ€‘μš”ν•œ 것은 μ–΄λ–€ 객체둜 μž κΈˆμ„ μ„€μ •ν–ˆλŠ”μ§€λ‹€.

μ•„λ§ˆ 같은 ν‚€λ₯Ό κ°€μ§€λŠ” λ©”μ„œλ“œλ₯Ό λ™μ‹œμ— μ‚¬μš© λΆˆκ°€ν•œ μ΄μœ λŠ” ν‚€κ°€ ν•˜λ‚˜μ΄κΈ° λ•Œλ¬ΈμΌ 것이닀. μ²˜μŒμ— abcκ°€ ν‚€λ₯Ό μ„ μ ν•˜κ³  ν•΄μ•Όν•  ν™œλ™μ„ 마치면 abcλŠ” ν‚€λ₯Ό λ°˜λ‚©ν•  것이닀. μ΄λ•Œ ν‚€λŠ” λ‹€μŒ μˆœμ„œμΈ bcd둜 λ„˜μ–΄κ°€μ§€ μ•ŠλŠ”λ‹€. bcd와 cdeκ°€ λ°˜λ‚©λœ ν‚€λ₯Ό κ°€μ§€κΈ° μœ„ν•΄ μ„œλ‘œ κ²½μŸν•  것이고 ν‚€λ₯Ό μ„ μ ν•œ λ©”μ„œλ“œκ°€ λ¨Όμ € ν™œλ™ν•˜κ²Œ λœλ‹€.

 

 

 

 


 

 

 

 

βœ”οΈ   μ“°λ ˆλ“œ 6κ°€μ§€ μƒνƒœ_ 552p

 

• NEW μƒνƒœ

: Thread 객체λ₯Ό new ν‚€μ›Œλ“œλ₯Ό μ΄μš©ν•΄ μƒμ„±ν•œ μ‹œμ μΈ μ‹€ν–‰ 이전 μƒνƒœ

Thread thread = new Thread() {
    @Override
    public void run() {
        for(long i = 0; i < 1000000000L; i++) {}
    }
}

 

 

• RUNNABLE μƒνƒœ

: start( ) λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•œ μƒνƒœ, μ‹€ν–‰ μƒνƒœλ‘œ μ–Έμ œλ“ μ§€ 갈 수 μžˆλŠ” μƒνƒœ

thread.start();

 

 

• TERMINATED μƒνƒœ

: run( ) λ©”μ„œλ“œκ°€ μ™„μ „νžˆ μ’…λ£Œλœ 싀행을 마친 μƒνƒœ

try {
    myTread.join();
} catch (InterruptedException e) {}

 

 

• TIMED_WAITING μƒνƒœ

: 정적 λ©”μ„œλ“œμΈ Thread.sleep λ˜λŠ” μΈμŠ€ν„΄μŠ€ λ©”μ„œλ“œμΈ join이 호좜된 μƒνƒœ

 Thread t1 = new Thread(() -> {
            try {
                Thread.sleep(2000); // 2초 λ™μ•ˆ κΈ°λ‹€λ¦Ό
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
Thread t2 = new Thread(() -> {
            try {
                t1.join(1000); // μ΅œλŒ€ 1초 λ™μ•ˆ t1을 κΈ°λ‹€λ¦Ό
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
μœ„μ˜ μ½”λ“œλŠ” Runnable μƒνƒœμ—μ„œ μΌμ‹œμ •μ§€ μƒνƒœλ‘œ μ „ν™˜λ˜λŠ” TIMED_WAITING μƒνƒœμ΄λ‹€. TIMED_WAITING μƒνƒœλŠ” 주둜 sleep(long millis)λ₯Ό ν˜ΈμΆœν•˜κ±°λ‚˜ join(long millis)κ°€ ν˜ΈμΆœλμ„ λ•Œλ‹€. 

Thread.sleep( )은 이 λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•œ μ“°λ ˆλ“œλ₯Ό μΌμ‹œ μ •μ§€ν•˜λΌλŠ” 의미둜 μΌμ‹œμ •μ§€ μ‹œκ°„ λ™μ•ˆ CPUλ₯Ό μ–΄λ–€ μ“°λ ˆλ“œκ°€ μ‚¬μš©ν•˜λ“  μƒκ΄€ν•˜μ§€ μ•ŠλŠ”λ‹€. μ“°λ ˆλ“œ 객체.join( ) λ©”μ„œλ“œλŠ” νŠΉμ • μ“°λ ˆλ“œ κ°μ²΄μ—κ²Œ 일정 μ‹œκ°„ λ™μ•ˆ CPUλ₯Ό ν• λ‹Ήν•˜λΌλŠ” μ˜λ―Έλ‹€.

μ“°λ ˆλ“œ t1은 sleep λ©”μ„œλ“œλ‘œ μΌμ‹œμ •μ§€κ°€ λ˜μ—ˆκ³  2초의 μ‹œκ°„λ™μ•ˆ μ–΄λ–€ μ“°λ ˆλ“œκ°€ CPUλ₯Ό μ‚¬μš©ν•˜λ“  μ‹ κ²½μ“°μ§€ μ•Šμ„ 것이닀. κ·ΈλŸ¬λ‚˜ μ“°λ ˆλ“œ t2λŠ” join λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν–ˆκΈ°μ— t2κ°€ μž μ‹œ 멈좘 1초 λ™μ•ˆ t1 μ“°λ ˆλ“œκ°€ CPUλ₯Ό μ‚¬μš©ν•˜λ„λ‘ ν–ˆλ‹€.

 

 

 

• BLOCKED μƒνƒœ

: 동기화 λ©”μ„œλ“œ λ˜λŠ” 동기화 블둝을 μ‹€ν–‰ν•˜κ³ μž ν•  λ•Œ 이미 λ‹€λ₯Έ μ“°λ ˆλ“œκ°€ ν•΄λ‹Ή μ˜μ—­μ„ μ‹€ν–‰ν•˜κ³  μžˆλŠ” 경우 λ°œμƒ.

Thread t1 = new Thread("thread1") {
    public void run() {
        mc.syncMethod();
    };
};  

Thread t2 = new Thread("thread2") {
    public void run() {
        mc.syncMethod();
    };
}; 

Thread t3 = new Thread("thread3") {
    public void run() {
        mc.syncMethod();
    };
};
μ“°λ ˆλ“œ t1이 λ¨Όμ € μ‹€ν–‰ν•˜κ³  μžˆμ„ λ•Œ, t1이 싀행을 μ™„λ£Œν•˜κ³  ν•΄λ‹Ή 동기화 μ˜μ—­μ˜ μ—΄μ‡ λ₯Ό λ°˜λ‚©ν•  λ•ŒκΉŒμ§€ κΈ°λ‹€λ €μ•Όν•œλ‹€. μ΄λ•Œ 이런 상황을 BLOCKED μƒνƒœλΌκ³  ν•œλ‹€. 

t1이 λ°˜λ‚©μ„ ν•˜κ²Œ 되면 κ·Έ λ‹€μŒ μˆœμ„œμΈ t2κ°€ ν‚€λ₯Ό κ°€μ§ˆ 것 κ°™μ§€λ§Œ 사싀 κ·Έλ ‡μ§€ μ•Šλ‹€. ν‚€κ°€ λ°˜λ‚©λœ μˆœκ°„λΆ€ν„° t2와 t3λŠ” μ„œλ‘œ ν‚€λ₯Ό κ°€μ§€κΈ° μœ„ν•΄ κ²½μŸν•  것이닀. κ·Έλ ‡κ²Œ λ¨Όμ € ν‚€λ₯Ό κ°€μ§€κ²Œ 된 μ“°λ ˆλ“œκ°€ t1 λ‹€μŒμœΌλ‘œ μ‹€ν–‰ν•˜κ²Œ 될 것이닀.
void startAll() {
    t1.start();
    t2.start();
    t3.start();
}
startAll λ©”μ„œλ“œμ—μ„œ t1, t2, t3 μ“°λ ˆλ“œκ°€ λ™μ‹œμ— μ‹€ν–‰ν•˜λ €κ³  ν•œλ‹€. 그러면 λ‹Ήμ—°ν•˜κ²Œ t1, t2, t3λŠ” κ²½μŸν•  것이고 ν‚€λ₯Ό μ°¨μ§€ν•œ μ“°λ ˆλ“œ λ¨Όμ € μ‹€ν–‰λ˜λ©° λ‚˜λ¨Έμ§€ 두 μ“°λ ˆλ“œλŠ” BLOCKED μƒνƒœκ°€ 될 것이닀.

 

 


• WAITING μƒνƒœ

: μ“°λ ˆλ“œκ°€ λ¬΄ν•œμ • 기닀리고 μžˆλŠ” μƒνƒœ

Thread t = new Thread(() -> {
            synchronized (lock) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

 

μ‹œκ°„μ„ μ§€μ •ν•˜μ§€ μ•Šμ€ join λ©”μ„œλ“œ λ˜λŠ” object.wait λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜κ²Œ 되면 WAITING μƒνƒœκ°€ λœλ‹€. join은 λ‹€λ₯Έ μ“°λ ˆλ“œκ°€ λλ‚ λ•ŒκΉŒμ§€ κΈ°λ‹€λ €μ•Όν•˜κ³  waitλŠ” notify( )둜 깨울 수 μžˆλ‹€. 

lock 객체둜 μž κΈˆμ„ 건 μ“°λ ˆλ“œ tλŠ” lock.wait( )으둜 lock을 잠깐 λ°˜λ‚©ν–ˆλ‹€. μ–Έμ œκΉŒμ§€ λ°˜λ‚©ν• μ§€ μ‹œκ°„μ„ μ§€μ •ν•˜μ§€ μ•Šμ•˜κΈ° λ•Œλ¬Έμ— notify( )둜 ν˜ΈμΆœν•˜μ—¬ WAITING μƒνƒœμ—μ„œ λΉ μ Έλ‚˜μ˜€λ„λ‘ ν•΄μ•Όν•œλ‹€.
synchronized (lock) {
    lock.notify(); 
        }