λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
Backend🌱/Java

[μžλ°”/Java] μ“°λ ˆλ“œ(thread)

by κΈ°λ©°λˆ… 2023. 1. 5.

μ“°λ ˆλ“œ(thread)

  • ν”„λ‘œμ„ΈμŠ€ : μ‹€ν–‰ 쀑인 ν”„λ‘œκ·Έλž¨, μžμ›(resources)κ³Ό μ“°λ ˆλ“œλ‘œ ꡬ성 = 곡μž₯
  • μ“°λ ˆλ“œ : ν”„λ‘œμ„ΈμŠ€ λ‚΄μ—μ„œ μ‹€μ œ μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” 것. λͺ¨λ“  ν”„λ‘œμ„ΈμŠ€λŠ” μ΅œμ†Œν•œ ν•˜λ‚˜μ˜ μ“°λ ˆλ“œλ₯Ό κ°€μ§€κ³  μžˆλ‹€. = 일꾼

μš°λ¦¬κ°€ μ‚¬μš©ν•˜κ³  μžˆλŠ” λŒ€λΆ€λΆ„ ν”„λ‘œκ·Έλž¨μ€ μ•„λž˜μ™€ 같이 λ©€ν‹° μ“°λ ˆλ“œ ν”„λ‘œμ„ΈμŠ€μΈ 것을 확인할 수 μžˆλ‹€.

그리고 ν•˜λ‚˜μ˜ μƒˆλ‘œμš΄ ν”„λ‘œμ„ΈμŠ€λ₯Ό μƒμ„±ν•˜λŠ” 것보닀 ν•˜λ‚˜μ˜ μƒˆλ‘œμš΄ μ“°λ ˆλ“œλ₯Ό μƒμ„±ν•˜λŠ” 것이 더 적은 λΉ„μš©μ΄ λ“ λ‹€!!! κ·Έλ ‡λ‹€κ³  λ©€ν‹°μ“°λ ˆλ“œ ν”„λ‘œκ·Έλž˜λ°μ΄ μž₯점만 μžˆλŠ” 것은 μ•„λ‹ˆλ‹€.

 

  • μž₯점
    • μ‹œμŠ€ν…œ μžμ›μ„ 보닀 효율적으둜 μ‚¬μš©ν•  수 μžˆλ‹€.
    • CPU의 μ‚¬μš©λ₯ μ„ ν–₯μƒμ‹œν‚¨λ‹€.
    • μ‚¬μš©μžμ— λŒ€ν•œ 응닡성이 ν–₯μƒλœλ‹€.
    • μž‘μ—…μ΄ λΆ„λ¦¬λ˜μ–΄ μ½”λ“œκ°€ κ°„κ²°ν•΄μ§„λ‹€.
  • 단점(μžμ›μ„ κ³΅μœ ν•˜λŠ” 데 μžˆμ–΄ λ¬Έμ œλ°œμƒ)
    • 동기화에 μ£Όμ˜ν•΄μ•Ό ν•œλ‹€.
    • κ΅μ°©μƒνƒœκ°€ λ°œμƒν•˜μ§€ μ•Šλ„λ‘ μ£Όμ˜ν•΄μ•Ό ν•œλ‹€.
    • 각 μ“°λ ˆλ“œκ°€ 효율적으둜 κ³ λ₯΄κ²Œ 싀행될 수 있게 ν•΄μ•Ό ν•œλ‹€.

참고둜 μ“°λ ˆλ“œμ˜ μ’…λ₯˜μ—λŠ” 일반 μ“°λ ˆλ“œμ™€ 데λͺ¬ μ“°λ ˆλ“œκ°€ μžˆλ‹€. μ΄λŠ” μ•„λž˜μ— μΆ”κ°€λ‘œ μ •λ¦¬ν•˜μ˜€λ‹€.


μ“°λ ˆλ“œμ˜ κ΅¬ν˜„κ³Ό μ‹€ν–‰

 1.  Thread클래슀λ₯Ό 상속

class MyThread extends Thread{
	public void run() { //Thread클래슀의 run()을 μ˜€λ²„λΌμ΄λ”©
    	//μž‘μ—…λ‚΄μš©
    }
}

 2.  RunnableμΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„

class MyThread2 implements Runnable{
	public void run() { //RunnableμΈν„°νŽ˜μ΄μŠ€μ˜ μΆ”μƒλ©”μ„œλ“œ run()을 κ΅¬ν˜„
    	//μž‘μ—…λ‚΄μš©
    }
}

 3.  μ“°λ ˆλ“œ μ‹€ν–‰

//1번 방법
MyThread t1 = new MyThread(); //μ“°λ ˆλ“œμ˜ 생성
t1.start(); //μ“°λ ˆλ“œμ˜ μ‹€ν–‰

//2번 방법
Runnable r = new MyThread2(); //μ“°λ ˆλ“œμ˜ 생성
Thread t2 = new Thread(r); // Thread(Runnable r)
t2.start(); //μ“°λ ˆλ“œμ˜ μ‹€ν–‰

 

 4.  μ“°λ ˆλ“œ κ΅¬ν˜„ 클래슀

Thread클래슀λ₯Ό μƒμ†λ°›μœΌλ©΄, μžμ† ν΄λž˜μŠ€μ—μ„œ 쑰상인 Thread클래슀의 λ©”μ„œλ“œλ₯Ό 직접 ν˜ΈμΆœν•  수 μžˆμ§€λ§Œ, Runnable을 κ΅¬ν˜„ν•˜λ©΄ Thread클래슀의 staticλ©”μ„œλ“œμΈ currentThread()λ₯Ό ν˜ΈμΆœν•˜μ—¬ μ“°λ ˆλ“œμ— λŒ€ν•œ μ°Έμ‘°λ₯Ό μ–»μ–΄ μ™€μ•Όλ§Œ 호좜이 κ°€λŠ₯ν•˜λ‹€.

 

 

μ“°λ ˆλ“œμ˜ 싀행을 ν•˜κΈ° μœ„ν•΄μ„œλŠ” μ“°λ ˆλ“œ 생성 ν›„ start() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•΄μ•Ό μ“°λ ˆλ“œκ°€ μž‘μ—…μ„ μ‹œμž‘ν•œλ‹€. 그리고 μ“°λ ˆλ“œκ°€ μ—¬λŸ¬ 개일 경우 OS의 μŠ€μΌ€μ₯΄λŸ¬κ°€ μ‹€ν–‰ μˆœμ„œλ₯Ό κ²°μ •ν•œλ‹€. λ˜ν•œ, ν•œλ²ˆ μ‹œν–‰μ΄ μ’…λ£Œλœ μ“°λ ˆλ“œλŠ” λ‹€μ‹œ μ‹€ν–‰ν•  수 μ—†λ‹€!! 즉, ν•˜λ‚˜μ˜ μ“°λ ˆλ“œμ— λŒ€ν•΄ start()κ°€ ν•œ 번만 호좜될 수 μžˆλ‹€λŠ” λœ»μ΄λ‹€.


start()와 run()

μ“°λ ˆλ“œλ₯Ό μ‹€ν–‰μ‹œν‚¬ λ•Œ run()이 μ•„λ‹Œ start() ν˜ΈμΆœν•œλ‹€λŠ” 것이 의문이 λ“€ 것이닀. μ“°λ ˆλ“œκ°€ μ‹€ν–‰λ˜λŠ” 과정에 λŒ€ν•΄μ„œ μ‚΄νŽ΄λ³΄μž.

  1. main λ©”μ„œλ“œμ—μ„œ μ“°λ ˆλ“œμ˜ start()λ₯Ό ν˜ΈμΆœν•œλ‹€.
  2. start()λŠ” μƒˆλ‘œμš΄ μ“°λ ˆλ“œλ₯Ό μƒμ„±ν•˜κ³ , μ“°λ ˆλ“œκ°€ μž‘μ—…ν•˜λŠ”λ° μ‚¬μš©λ  ν˜ΈμΆœμŠ€νƒμ„ μƒμ„±ν•œλ‹€. 
  3. μƒˆλ‘œ μƒμ„±λœ ν˜ΈμΆœμŠ€νƒμ— run()이 ν˜ΈμΆœλ˜μ–΄, μ“°λ ˆλ“œκ°€ λ…λ¦½λœ κ³΅κ°„μ—μ„œ μž‘μ—…μ„ μˆ˜ν–‰ν•œλ‹€.
  4. μ΄μ œλŠ” ν˜ΈμΆœμŠ€νƒμ΄ 2κ°œμ΄λ―€λ‘œ μŠ€μΌ€μ€„λŸ¬κ°€ μ •ν•œ μˆœμ„œμ— μ˜ν•΄μ„œ λ²ˆκ°ˆμ•„ κ°€λ©΄μ„œ μ‹€ν–‰λœλ‹€.
  5. run()의 μˆ˜ν–‰μ΄ μ’…λ£Œλœ μ“°λ ˆλ“œλŠ” ν˜ΈμΆœμŠ€νƒμ΄ λͺ¨λ‘ λΉ„μ›Œμ§€λ©΄μ„œ 이 μ“°λ ˆλ“œκ°€ μ‚¬μš©ν•˜λ˜ ν˜ΈμΆœμŠ€νƒμ€ 사라진닀.

이처럼 mainλ©”μ„œλ“œμ—μ„œ run()을 ν˜ΈμΆœν•˜λŠ” 것은 μƒμ„±λœ μ“°λ ˆλ“œλ₯Ό μ‹€ν–‰μ‹œν‚€λŠ” 것이 μ•„λ‹ˆλΌ λ‹¨μˆœνžˆ ν΄λž˜μŠ€μ— μ„ μ–Έ 된 λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λŠ” 것일 뿐이닀. λ˜ν•œ, λͺ¨λ“  μ“°λ ˆλ“œλŠ” 독립적인 μž‘μ—…μ„ μˆ˜ν–‰ν•˜κΈ° μœ„ν•΄ μžμ‹ λ§Œμ˜ ν˜ΈμΆœμŠ€νƒμ„ ν•„μš”λ‘œ ν•˜κΈ° λ•Œλ¬Έμ—, μƒˆλ‘œμš΄ μ“°λ ˆλ“œλ₯Ό μƒμ„±ν•˜κ³  μ‹€ν–‰μ‹œν‚¬ λ•Œλ§ˆλ‹€ μƒˆλ‘œμš΄ ν˜ΈμΆœμŠ€νƒμ΄ μƒμ„±λ˜κ³  μ“°λ ˆλ“œκ°€ μ’…λ£Œλ˜λ©΄ μž‘μ—…μ— μ‚¬μš©λœ ν˜ΈμΆœμŠ€νƒμ€ μ†Œλ©Έλœλ‹€.

그리고 mainλ©”μ„œλ“œμ˜ μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” 것도 μ“°λ ˆλ“œμ΄λ©°, 이λ₯Ό mainμ“°λ ˆλ“œλΌκ³  ν•œλ‹€.


μ‹±κΈ€μ“°λ ˆλ“œμ™€ λ©€ν‹°μ“°λ ˆλ“œ

  • μ‹±κΈ€μ“°λ ˆλ“œ : ν•˜λ‚˜μ˜ μ“°λ ˆλ“œλ‘œ 두 개의 μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” 경우

  • λ©€ν‹°μ“°λ ˆλ“œ : 두 개의 μ“°λ ˆλ“œλ‘œ λ‘κ°œμ˜ μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” 경우, OS μŠ€μΌ€μ€„λŸ¬κ°€ μ‹€ν–‰μˆœμ„œλ₯Ό κ²°μ •ν•˜κΈ°μ— μ‹€ν–‰ν•  λ•Œλ§ˆλ‹€ λ‹€λ₯΄κ²Œ λ‚˜νƒ€λ‚œλ‹€.

μ‹±κΈ€μ“°λ ˆλ“œλ‘œ ν”„λ‘œκ·Έλž¨μ„ μ‹€ν–‰ν•œ 것과 λ©€ν‹°μ“°λ ˆλ“œλ‘œ μ‹€ν–‰ν•œ 것을 비ꡐ해보면 λ©€ν‹°μ“°λ ˆλ“œλ‘œ μž‘μ—…ν•  λ•Œ λ―Έμ„Έν•˜κ²Œ 더 λ§Žμ€ μ‹œκ°„μ΄ 걸리게 되며 μ΄μœ λŠ” 두 가지이닀. 첫 번째둜 두 μ“°λ ˆλ“œκ°€ λ²ˆκ°ˆμ•„κ°€λ©΄μ„œ μž‘μ—…μ„ μ²˜λ¦¬ν•˜κΈ° λ•Œλ¬Έμ— μ“°λ ˆλ“œκ°„μ˜ μž‘μ—…μ „ν™˜μ‹œκ°„μ΄ μ†Œμš”λ˜κΈ° λ•Œλ¬Έμ΄κ³ , 두 λ²ˆμ§ΈλŠ” ν•œ μ“°λ ˆλ“œκ°€ 화면에 좜λ ₯ν•˜κ³  μžˆλŠ” λ™μ•ˆ λ‹€λ₯Έ μ“°λ ˆλ“œλŠ” 좜λ ₯이 λλ‚˜κΈ°λ₯Ό κΈ°λ‹€λ €μ•Όν•˜λŠ”λ°, μ΄λ•Œ λ°œμƒν•˜λŠ” λŒ€κΈ°μ‹œκ°„ λ•Œλ¬Έμ΄λ‹€. ν•˜μ§€λ§Œ μž…μΆœλ ₯κ³Ό 같이 두 μ“°λ ˆλ“œκ°€ μ„œλ‘œ λ‹€λ₯Έ μžμ›μ„ μ‚¬μš©ν•˜λŠ” μž‘μ—…μ˜ κ²½μš°μ—λŠ” μ‹±κΈ€μ“°λ ˆλ“œ ν”„λ‘œμ„ΈμŠ€λ³΄λ‹€ λ©€ν‹° μ“°λ ˆλ“œ ν”„λ‘œμ„ΈμŠ€κ°€ 더 νš¨μœ¨μ μ΄λ‹€.


μ“°λ ˆλ“œμ˜ μš°μ„ μˆœμœ„(priority of thread)

μ“°λ ˆλ“œλŠ” μž‘μ—…μ˜ μ€‘μš”λ„μ— 따라 μš°μ„ μˆœμœ„λ₯Ό λ‹€λ₯΄κ²Œ ν•˜μ—¬ νŠΉμ • μ“°λ ˆλ“œκ°€ 더 λ§Žμ€ μž‘μ—…μ‹œκ°„μ„ κ°–κ²Œ ν•  수 μžˆλ‹€.


μ“°λ ˆλ“œ κ·Έλ£Ή

μ“°λ ˆλ“œ 그룹은 μ„œλ‘œ κ΄€λ ¨λœ μ“°λ ˆλ“œλ₯Ό 그룹으둜 λ¬Άμ–΄μ„œ 닀루기 μœ„ν•œ 것이닀. λͺ¨λ“  μ“°λ ˆλ“œλŠ” λ°˜λ“œμ‹œ ν•˜λ‚˜μ˜ μ“°λ ˆλ“œ 그룹에 ν¬ν•¨λ˜μ–΄ μžˆμ–΄μ•Όν•˜λŠ”λ° μ“°λ ˆλ“œ 그룹을 μ§€μ •ν•˜μ§€ μ•Šκ³  μƒμ„±ν•œ μ“°λ ˆλ“œλŠ” 'mainμ“°λ ˆλ“œ κ·Έλ£Ή'에 μ†ν•œλ‹€. λ˜ν•œ, μžμ‹ μ„ μƒμ„±ν•œ μ“°λ ˆλ“œ(λΆ€λͺ¨ μ“°λ ˆλ“œ)의 κ·Έλ£Ήκ³Ό μš°μ„ μˆœμœ„λ₯Ό μƒμ†λ°›λŠ”λ‹€.

 

μ“°λ ˆλ“œ 그룹의 λ©”μ„œλ“œλ“€μ€ ν•„μš”ν•  λ•Œ μ°Ύμ•„λ³΄μž~


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

일반 μ“°λ ˆλ“œ(non-daemon thread)의 μž‘μ—…μ„ λ•λŠ” 보쑰적인 역할을 μˆ˜ν–‰ν•˜λŠ” μ“°λ ˆλ“œμ΄λ‹€. λ”°λΌμ„œ, 일반 μ“°λ ˆλ“œκ°€ λͺ¨λ‘ μ’…λ£Œλ˜λ©΄ μžλ™μ μœΌλ‘œ μ’…λ£Œλœλ‹€. 데λͺ¬ μ“°λ ˆλ“œλŠ” κ°€λΉ„μ§€ 컬렉터, μžλ™μ €μž₯, ν™”λ©΄ μžλ™κ°±μ‹  등에 μ‚¬μš©λœλ‹€.

데λͺ¬ μ“°λ ˆλ“œλŠ” λ¬΄ν•œλ£¨ν”„μ™€ 쑰건문을 μ΄μš©ν•΄μ„œ μ‹€ν–‰ ν›„ λŒ€κΈ°ν•˜κ³  μžˆλ‹€κ°€ νŠΉμ • 쑰건이 만쑱되면 μž‘μ—…μ„ μˆ˜ν–‰ν•˜κ³  λ‹€μ‹œ λŒ€κΈ°ν•˜λ„λ‘ μž‘μ„±ν•œλ‹€.

참고둜 setDaemon(boolean on)은 λ°˜λ“œμ‹œ start() ν˜ΈμΆœν•˜κΈ° 전에 μ‹€ν–‰λ˜μ–΄μ•Ό ν•œλ‹€. κ·Έλ ‡μ§€ μ•ŠμœΌλ©΄ IllegalThreadStateException이 λ°œμƒν•œλ‹€.


μ“°λ ˆλ“œμ˜ μƒνƒœ

RUNNABLE은 μž‘μ—…μ„ λ‹€ λ§ˆμΉ λ•ŒκΉŒμ§€ μ‹€ν–‰ν•˜κ³  λ‹€μ‹œ λŒ€κΈ°ν•˜λŠ” μΌμ’…μ˜ μ€„μ„œκΈ° 단계라고 보면 λœλ‹€. 

그리고 μ“°λ ˆλ“œμ˜ μ‹€ν–‰μ œμ–΄ λ©”μ„œλ“œλ₯Ό ν™œμš©ν•΄μ„œ 보닀 효율적인 ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•  수 μžˆλ‹€.

 

sleep = 잠자기

join = νŠΉμ • μ“°λ ˆλ“œ μž‘μ—…ν•˜λŠ” κ±° 기닀리기

interrupt = 깨우기

suspend = μΌμ‹œμ •μ§€

resume = 재개

stop = μ™„μ „μ •μ§€

yield = μ–‘λ³΄ν•˜κΈ°


μ“°λ ˆλ“œ 동기화(synchronization)

λ©€ν‹° μ“°λ ˆλ“œ ν”„λ‘œμ„ΈμŠ€μ—μ„œλŠ” A μ“°λ ˆλ“œκ°€ μž‘μ—…μ„ λ‹€ λ§ˆμΉ˜μ§€ λͺ»ν•œ μƒνƒœμ—μ„œ B μ“°λ ˆλ“œλ‘œ μ°¨λ‘€κ°€ λ„˜μ–΄κ°”μ„ λ•Œ μ§„ν–‰κ³Όμ •μ—μ„œ 기쑴의 A μ“°λ ˆλ“œμ˜ μž‘μ—…μ— 영ν–₯을 λ―ΈμΉ  수 μžˆλ‹€. 이처럼 진행쀑인 μž‘μ—…μ΄ λ‹€λ₯Έ μ“°λ ˆλ“œμ—κ²Œ κ°„μ„­λ°›μ§€ μ•Šκ²Œ ν•˜λ €λ©΄ '동기화'κ°€ ν•„μš”ν•˜λ‹€.

μ“°λ ˆλ“œμ˜ λ™κΈ°ν™”λž€ ν•œ μ“°λ ˆλ“œκ°€ 진행쀑인 μž‘μ—…μ„ λ‹€λ₯Έ μ“°λ ˆλ“œκ°€ κ°„μ„­ν•˜μ§€ λͺ»ν•˜κ²Œ λ§‰λŠ” 것을 λ§ν•œλ‹€.

동기화λ₯Ό ν•˜λ €λ©΄ κ°„μ„­λ°›μ§€ μ•Šμ•„μ•Ό ν•˜λŠ” λ¬Έμž₯듀을 'μž„κ³„ μ˜μ—­'으둜 μ„€μ •ν•œλ‹€. μž„κ³„μ˜μ—­μ€ 락(lock)을 얻은 단 ν•˜λ‚˜μ˜ μ“°λ ˆλ“œλ§Œ μΆœμž…μ΄ κ°€λŠ₯ν•˜λ‹€.(객체 1κ°œμ— 락 1개)

 

  • synchronizationλ₯Ό μ΄μš©ν•œ 동기화

synchronized둜 μž„κ³„μ˜μ—­(lock이 κ±Έλ¦¬λŠ” μ˜μ—­)을 μ„€μ •ν•˜λŠ” 방법 2κ°€μ§€

μž„κ³„ μ˜μ—­μ€ ν•œ μ“°λ ˆλ“œλ‹Ή ν•œ 개만 μ‚¬μš©ν•  수 있기 λ•Œλ¬Έμ— μ˜μ—­μ„ μ΅œμ†Œν™” ν•΄μ•Όν•œλ‹€. μž„κ³„ μ˜μ—­μ€ λ©€ν‹° μ“°λ ˆλ“œ ν”„λ‘œκ·Έλž¨μ˜ μ„±λŠ₯을 μ’Œμš°ν•˜κΈ° λ•Œλ¬Έμ— κ°€λŠ₯ν•˜λ©΄ λ©”μ„œλ“œ 전체에 락을 κ±°λŠ” 1λ²ˆλ³΄λ‹€ 2번 λ°©λ²•μœΌλ‘œ μž„κ³„ μ˜μ—­μ„ μ΅œμ†Œν™”ν•΄μ„œ 보닀 효율적인 ν”„λ‘œκ·Έλž¨μ΄ λ˜λ„λ‘ λ…Έλ ₯ν•΄μ•Ό ν•œλ‹€.


wait()κ³Ό notify()

synchronized둜 λ™κΈ°ν™”ν•΄μ„œ 곡유 데이터λ₯Ό λ³΄ν˜Έν•˜λŠ” 것은 쒋은데 νŠΉμ • μ“°λ ˆλ“œκ°€ 객체의 락을 κ°€μ§„ μƒνƒœλ‘œ 였랜 μ‹œκ°„μ„ 보내지 μ•Šλ„λ‘ ν•˜λŠ” 것도 μ€‘μš”ν•˜λ‹€. 동기화λ₯Ό ν•˜κ²Œ 되면 λ‹€λ₯Έ μž‘μ—…λ“€μ΄ μ›ν™œνžˆ μ§„ν–‰λ˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ΄λ‹€. λ”°λΌμ„œ, λ™κΈ°ν™”μ˜ νš¨μœ¨μ„ 높이기 μœ„ν•΄ wait(), notify()λ₯Ό μ‚¬μš©ν•œλ‹€. μ΄λŠ” Objectν΄λž˜μŠ€μ— μ •μ˜λ˜μ–΄ 있으며, 동기화 블둝 λ‚΄μ—μ„œλ§Œ μ‚¬μš©ν•  수 μžˆλ‹€.

wait = 기닀리기, notify =  waiting poolμ—μ„œ λŒ€κΈ°μ€‘μΈ μ“°λ ˆλ“œ μ€‘μ˜ ν•˜λ‚˜λ₯Ό 깨우기, 톡보, μ•Œλ €μ£ΌκΈ° , notifyAll = waiting poolμ—μ„œ λŒ€κΈ°μ€‘μΈ λͺ¨λ“  μ“°λ ˆλ“œλ₯Ό 깨우기, 톡보, μ•Œλ €μ£ΌκΈ°

 

그런데 wait와 notify의 경우 λŒ€κΈ°ν•˜κ³  μžˆλŠ” 객체듀이 μ—¬λŸ¬κ°œμΌ λ•Œ ν˜ΈμΆœλ˜λŠ” λŒ€μƒμ΄ λΆˆλΆ„λͺ…ν•˜λ‹€. 

이처럼 μžμ‹ μ˜ 차둀인데도 μ›ν•˜λŠ” 것이 μ—†κ±°λ‚˜ λ˜λŠ” μ§€λ…ν•˜κ²Œ 운이 λ‚˜λΉ  ν•œ μ“°λ ˆλ“œκ°€ 계속 톡지λ₯Ό λ°›μ§€ λͺ»ν•˜κ³  μ˜€λž«λ™μ•ˆ κΈ°λ‹€λ¦¬κ²Œ λ˜λŠ”λ° 이것을 'κΈ°μ•„(starvation) ν˜„μƒ'이라고 ν•œλ‹€. 이 ν˜„μƒμ„ λ§‰κΈ°μœ„ν•΄ notifyAll()을 μ‚¬μš©ν•΄μ•Ό ν•œλ‹€. μ΄κ²ƒμœΌλ‘œ κΈ°μ•„ν˜„μƒμ€ λ§‰μ•˜μ§€λ§Œ λΆˆν•„μš”ν•˜κ²Œ λ§Žμ€ μ“°λ ˆλ“œμ™€ lock을 μ–»κΈ° μœ„ν•΄ κ²½μŸν•˜κ²Œ λœλ‹€. 이λ₯Ό '경쟁 μƒνƒœ(race condition)'라고 ν•œλ‹€. 경쟁 μƒνƒœλ₯Ό κ°œμ„ ν•˜κΈ° μœ„ν•΄ μ›ν•˜λŠ” μ“°λ ˆλ“œλ₯Ό κ΅¬λ³„ν•΄μ„œ ν†΅μ§€ν•˜λŠ” 것이 ν•„μš”ν•œλ° μ΄λ•Œ Lockκ³Ό Condition을 μ΄μš©ν•œλ‹€.


Lockκ³Ό Condition을 μ΄μš©ν•œ 동기화

동기화할 수 μžˆλŠ” 방법은 synchronizedλΈ”λŸ­ 외에도 'java.util.concurrent.locks'νŒ¨ν‚€μ§€κ°€ μ œκ³΅ν•˜λŠ” lockν΄λž˜μŠ€λ“€μ„ μ΄μš©ν•˜λŠ” 방법이 μžˆλ‹€. synchronizedλΈ”λŸ­μœΌλ‘œ 동기화λ₯Ό ν•˜λ©΄ μžλ™μ μœΌλ‘œ lock이 잠기고 풀리기 λ•Œλ¬Έμ— νŽΈλ¦¬ν•˜λ‹€. λΈ”λŸ­ λ‚΄μ—μ„œ μ˜ˆμ™Έκ°€ λ°œμƒν•΄λ„ lock을 μžλ™μ μœΌλ‘œ ν’€λ¦°λ‹€. κ·ΈλŸ¬λ‚˜ λ•Œλ‘œλŠ” 같은 λ©”μ„œλ“œ λ‚΄μ—μ„œλ§Œ lock을 κ±Έ 수 μžˆλ‹€λŠ” μ œμ•½μ΄ λΆˆνŽΈν•˜κΈ°λ„ ν•˜λ‹€. 그럴 λ•Œ lock클래슀λ₯Ό μ‚¬μš©ν•œλ‹€. lockν΄λž˜μŠ€λ“€μ€ μˆ˜λ™μœΌλ‘œ lock을 잠그고 ν•΄μ œν•΄μ•Ό ν•œλ‹€. lock클래슀의 μ’…λ₯˜λŠ” λ‹€μŒκ³Ό 같이 3κ°€μ§€κ°€ μžˆλ‹€.

 

  • ReentrantLock : μž¬μ§„μž…μ΄ κ°€λŠ₯ν•œ lock, κ°€μž₯ 일반적인 배타 lock

μš°λ¦¬κ°€ lock이라고 λΆˆλŸ¬μ™”λ˜ κ²ƒμœΌλ‘œ νŠΉμ • μ‘°κ±΄μ—μ„œ lock을 ν’€κ³  λ‚˜μ€‘μ— λ‹€μ‹œ lock을 μ–»κ³  μž„κ³„μ˜μ—­μœΌλ‘œ λ“€μ–΄μ™€μ„œ μ΄ν›„μ˜ μž‘μ—…μ„ μˆ˜ν–‰ν•  수 있기 λ•Œλ¬Έμ— 'μž¬μ§„μž…ν•  수 μžˆλŠ”'μ΄λΌλŠ” 단어가 뢙은 것이닀. 

 

  • ReentrantReadWriteLock : μ½κΈ°μ—λŠ” 곡유적이고, μ“°κΈ°μ—λŠ” 배타적인 lock

ReentrantLock은 λ‹€λ₯Έ 것은 λ°°μ²™ν•˜κ³  μžκΈ°λ§Œμ„ μƒκ°ν•˜λŠ” 배타적인 lockμ΄λΌμ„œ 무쑰건 lock이 μžˆμ–΄μ•Όλ§Œ μž„κ³„ μ˜μ—­μ˜ μ½”λ“œλ₯Ό μˆ˜ν–‰ν•  수 μžˆμ§€λ§Œ, ReentrantReadWriteLockλŠ” 읽기 lock이 걸렀있으면, λ‹€λ₯Έ μ“°λ ˆλ“œκ°€ 읽기 lock을 μ€‘λ³΅ν•΄μ„œ κ±Έκ³  읽기λ₯Ό μˆ˜ν–‰ν•  수 μžˆλ‹€. μ½κΈ°λŠ” λ‚΄μš©μ„ λ³€κ²½ν•˜μ§€ μ•ŠκΈ°μ— λ™μ‹œμ— μ—¬λŸ¬ μ“°λ ˆλ“œκ°€ 읽어도 λ¬Έμ œκ°€ λ˜μ§€ μ•ŠλŠ”λ‹€. κ·ΈλŸ¬λ‚˜ 읽기 lock이 κ±Έλ¦° μƒνƒœμ—μ„œ μ“°κΈ° lock을 κ±°λŠ” 것은 ν—ˆμš©λ˜μ§€ μ•ŠλŠ”λ‹€. 

 

  • StampedLock : ReentrantReadWriteLock에 낙관적인 lock의 κΈ°λŠ₯을 μΆ”κ°€

lock을 κ±Έκ±°λ‚˜ ν•΄μ§€ν•  λ•Œ 'μŠ€νƒ¬ν”„(longνƒ€μž…μ˜ μ •μˆ˜κ°’)'λ₯Ό μ‚¬μš©ν•˜λ©°, 읽기와 μ“°κΈ°λ₯Ό μœ„ν•œ lock외에 '낙관적 읽기 lock'이 μΆ”κ°€λœ 것이닀. 읽기 lock이 걸렀있으면, μ“°κΈ° lock을 μ–»κΈ° μœ„ν•΄μ„œλŠ” 읽기 lock이 풀릴 λ•ŒκΉŒμ§€ κΈ°λ‹€λ €μ•Όν•˜λŠ”λ° μ΄λŠ” μ“°κΈ° lock에 μ˜ν•΄ λ°”λ‘œ ν’€λ¦°λ‹€. κ·Έλž˜μ„œ 낙관적 읽기에 μ‹€νŒ¨ν•˜λ©΄, 읽기 lock을 μ–»μ–΄μ„œ λ‹€μ‹œ 읽어 와야 ν•œλ‹€. 무쑰건 읽기 lock을 κ±Έμ§€ μ•Šκ³ , 쓰기와 읽기가 μΆ©λŒν•  λ•Œλ§Œ μ“°κΈ°κ°€ λλ‚œ 후에 읽기 lock을 κ±°λŠ” 것이닀.

 

 

λ‹€μŒμ€ μ“°λ ˆλ“œλ₯Ό κ΅¬λΆ„ν•΄μ„œ 톡지할 수 μžˆλ„λ‘ ν•˜λŠ” Condition이닀. μ›ν•˜λŠ” μ“°λ ˆλ“œ ν˜ΈμΆœμ„ μœ„ν•œ Condition을 각각 λ§Œλ“€μ–΄μ„œ waiting poolμ—μ„œ λ”°λ‘œ 기닀리도둝 ν•˜λŠ” 것이닀. ex) μš”λ¦¬μ‚¬ μ“°λ ˆλ“œλ₯Ό μœ„ν•œ Condition, μ†λ‹˜ μ“°λ ˆλ“œλ₯Ό μœ„ν•œ Condition

μ΄λ•ŒλŠ” wait(), notify()λŒ€μ‹  Condition의 await()와 signal()을 μ‚¬μš©ν•œλ‹€. 이둜써, ν†΅μ§€μ˜ λŒ€μƒμ΄ λͺ…ν™•νžˆ ꡬ뢄할 수 있게 λœλ‹€.


volatile

μš”μ¦˜μ—” λŒ€λΆ€λΆ„ λ©€ν‹° μ½”μ–΄ ν”„λ‘œμ„Έμ„œκ°€ μž₯착된 컴퓨터λ₯Ό μ‚¬μš©ν•˜λ©° μ΄λŠ” μ½”μ–΄λ§ˆλ‹€ λ³„λ„μ˜ μΊμ‹œλ₯Ό κ°€μ§€κ³  μžˆλ‹€. μ½”μ–΄λŠ” λ©”λͺ¨λ¦¬μ—μ„œ μ½μ–΄μ˜¨ 값을 μΊμ‹œμ— μ €μž₯ν•˜κ³  μΊμ‹œμ—μ„œ 값을 μ½μ–΄μ„œ μž‘μ—…ν•œλ‹€. λ‹€μ‹œ 같은 값을 μ½μ–΄μ˜¬ λ•ŒλŠ” λ¨Όμ € μΊμ‹œμ— μžˆλŠ”μ§€ ν™•μΈν•˜κ³  없을 λ•Œλ§Œ λ©”λͺ¨λ¦¬μ—μ„œ μ½μ–΄μ˜¨λ‹€. κ·ΈλŸ¬λ‹€λ³΄λ‹ˆ 도쀑에 λ©”λͺ¨λ¦¬μ— μ €μž₯된 λ³€μˆ˜μ˜ 값이 λ³€κ²½λ˜μ—ˆλŠ”λ°λ„ μΊμ‹œμ— μ €μž₯된 값이 κ°±μ‹ λ˜μ§€ μ•Šμ•„μ„œ λ©”λͺ¨λ¦¬μ— μ €μž₯된 값이 λ‹€λ₯Έ κ²½μš°κ°€ λ°œμƒν•œλ‹€. κ·Έλž˜μ„œ ν•œ λ³€μˆ˜μ˜ 값이 λ°”λ€Œμ—ˆλŠ”λ°λ„ μ“°λ ˆλ“œκ°€ λ©ˆμΆ”μ§€ μ•Šκ³  계속 μ‹€ν–‰λ˜μ–΄ μ›ν•˜μ§€ μ•ŠλŠ” μž‘μ—…μ΄ μ§„ν–‰λ˜λŠ” 것이닀.

이에 λ³€μˆ˜ μ•žμ— volatile을 뢙이면, μ½”μ–΄κ°€ λ³€μˆ˜μ˜ 값을 μ½μ–΄μ˜¬ λ•Œ μΊμ‹œκ°€ μ•„λ‹Œ λ©”λͺ¨λ¦¬μ—μ„œ μ½μ–΄μ˜€κΈ° λ•Œλ¬Έμ— μΊμ‹œμ™€ λ©”λͺ¨λ¦¬κ°„μ˜ κ°’μ˜ λΆˆμΌμΉ˜κ°€ ν•΄κ²°λœλ‹€. λ³€μˆ˜μ— volatile을 λΆ™μ΄λŠ” λŒ€μ‹ μ— synchronizedλΈ”λŸ­μ„ μ‚¬μš©ν•΄λ„ 같은 효과λ₯Ό 얻을 수 μžˆλ‹€. μ“°λ ˆλ“œκ°€ synchronizedλΈ”λŸ­μœΌλ‘œ λ“€μ–΄κ°ˆ λ•Œμ™€ λ‚˜μ˜¬ λ•Œ, μΊμ‹œμ™€ λ©”λͺ¨λ¦¬κ°„μ˜ 동기화가 이루어지기 λ•Œλ¬Έμ΄λ‹€.