μ°λ λ λκΈ°νλ?
μ±κΈμ°λ λ νλ‘μΈμ€λ νλμ λ©μΈ μ°λ λλ§ μμ μ μννλ νλ‘μΈμ€λ₯Ό λ»νλ©°, λ©ν°μ°λ λ νλ‘μΈμ€λ λ©μΈ μ°λ λ ν¬ν¨ λ κ° μ΄μμ μ°λ λκ° λμμ μμ μ μννλ νλ‘μΈμ€λ₯Ό λ»ν©λλ€.
κ·Έλ κΈ° λλ¬Έμ μ±κΈμ°λ λ νλ‘μΈμ€μ κ²½μ° νλ‘μΈμ€μ μμμ κ°μ§κ³ μμ νλ ν° λ¬Έμ κ° μμ§λ§, λ©ν°μ°λ λ νλ‘μΈμ€ κ°μ κ²½μ° μ¬λ¬ μ°λ λκ° κ°μ νλ‘μΈμ€ λ΄μ μμμ 곡μ ν΄μ μμ νκΈ° λλ¬Έμ μλ‘μ μμ μ μν₯μ μ€ μ λ°μ μμ΅λλ€. λ§μ½μ μ°λ λ Aκ° νλμ 곡μ μμμ κ°μ§κ³ μμ μ μννλ€κ° μ°λ λ Bμκ² μ μ΄κΆμ΄ λμ΄κ°μ λ, μ°λ λ Aκ° μμ νλ 곡μ μμμ μ°λ λBκ° μμλ‘ κ±΄λλ Έλ€λ©΄ μ°λ λAλ μνλ κ²°κ³Όλ₯Ό μ»μ μ μμ κ²μ λλ€.
μ΄λ¬ν μΌμ λ°©μ§νκΈ° μν΄μλ ν μ°λ λκ° νΉμ μμ μ λλ§μΉκΈ° μ κΉμ§ λ€λ₯Έ μ°λ λμ μν΄ λ°©ν΄λ°μ§ μλλ‘ ν΄μΌνλ©°, κ·Έλμ λμ λ κ°λ μ΄ μκ³μμ(Critical Section)κ³Ό μ κΈ(Lock) μ λλ€. μ¦, 곡μ λ°μ΄ν°λ₯Ό μ¬μ©νλ μ½λ μμμ μκ³μμμΌλ‘ μ§μ νκ³ κ³΅μ λ°μ΄ν°κ° κ°μ§κ³ μλ Lockμ νλν νλμ μ°λ λλ§ μ κ·Όν μ μλλ‘ νλ κ²μ λλ€. μ΄μ²λΌ ν μ°λ λκ° μ§νμ€μΈ μμ μ λ€λ₯Έ μ°λ λκ° κ°μνμ§ λͺ»νλλ‘ νλ κ²μ 'μ°λ λμ λκΈ°ν' λΌκ³ ν©λλ€.
synchronized ν€μλμ λ©μλ
κ°μ₯ κ°λ¨ν λκΈ°ν λ°©λ²μ synchronized ν€μλλ₯Ό μ΄μ©ν λκΈ°ν λ°©λ²μ λλ€. μ΄ ν€μλλ μκ³μμμ μ€μ νλλ° μ¬μ©λ©λλ€. λ°©λ²μλ λκ°μ§κ° μλλ°, λ€μκ³Ό κ°μ΅λλ€.
1. λ©μλ μ 체λ₯Ό μκ³μμμΌλ‘ μ€μ
public synchronized void Method() {}
ν΄λΉ λ°©λ²μΌλ‘ μ§ννκ² λλ©΄ λ©μλ μ μ²΄κ° μκ³μμμΌλ‘ μ€μ λ©λλ€. μ°λ λλ synchronized λ©μλκ° νΈμΆλ μμ λΆν° ν΄λΉ λ©μλκ° ν¬ν¨λ κ°μ²΄μ lockμ μ»μ΄ μ§ννλ€κ° λ©μλκ° μ’ λ£λλ©΄ lockμ λ°λ©νκ² λ©λλ€.
2. μΌλΆ μμλ§μ μκ³μμμΌλ‘ μ€μ
synchronized(κ°μ²΄) {}
ν΄λΉ λ°©λ²μΌλ‘ μ§ννκ² λλ©΄ λ©μλ μ μ²΄κ° μλ, λ©μλμ νΉμ λΆλΆμ μκ³μμμΌλ‘ μ€μ ν μ μμ΅λλ€. μ΄λ μ°Έμ‘°λ³μλ λ½μ κ±Έκ³ μνλ κ°μ²΄λ₯Ό μ°Έμ‘°νλ κ²μ΄μ¬μΌ ν©λλ€. (μ°Έκ³ λ‘ κ°μ²΄λΉ νλμ λ½μ κ°μ§κ² λ©λλ€.) κ΄νΈλ‘ κ°μΈκ³ μλ λΆλΆμ΄ synchronizedλΈλ‘ μμμ΄λ©°, ν΄λΉ μμμΌλ‘ λ€μ΄κ°λ©΄μ μ§μ λ κ°μ²΄μ lockμ μ»κ²λκ³ ν΄λΉ μμμ λ²μ΄λ λ lockμ λ°λ©νκ² λ©λλ€.
λ λ°©λ² λͺ¨λ lock νλ λ°λ©μ΄ μλμΌλ‘ μ΄λ£¨μ΄μ§λ―λ‘ κ°λ°μλ λ¨μν μκ³ μμλ§ μ€μ ν΄μ£Όλ©΄ λ©λλ€. μκ³μμμ λ©ν°μ°λ λ νλ‘κ·Έλ¨μ μ±λ₯μ μ’μ°νκΈ° λλ¬Έμ κ°λ₯νλ©΄ λ©μλ μ 체μ λ½μ κ±°λ κ²λ³΄λ€, synchronizedλΈλμΌλ‘ μκ³μμμ μ΅μννμ¬ ν¨μ¨μ μΈ νλ‘κ·Έλ¨μ΄ λλλ‘ λ Έλ ₯ν΄μΌ ν©λλ€.
wait(), notify()
synchronizedλ‘ λκΈ°ννμ¬ κ³΅μ λ°μ΄ν°λ₯Ό 보νΈνλ κ²λ μ€μνμ§λ§, νΉμ μ°λ λκ° κ°μ²΄μ λ½μ κ°μ§ μνλ‘ μ€λ μκ°μ 보λ΄μ§ μλλ‘ νλ κ²λ κ΅μ₯ν μ€μν©λλ€. κ·Έλμ κ³ μλ κ²μ΄ λ°λ‘ wait() κ³Ό notify()μ λλ€. λκΈ°νλ μκ³μμμ μ½λλ₯Ό μννλ€κ° μμ μ μνν μν©μ΄ μλλΌλ©΄, wait()μ νΈμΆνμ¬ μ°λ λκ° λ½μ λ°λ©νκ³ λκΈ°μνλ‘ λμ νκ² λ©λλ€. κ·Έλ¬λ©΄ λ€λ₯Έ μ°λ λκ° λ½μ μ»μ΄ ν΄λΉ κ°μ²΄μ λν μμ μ μνν μ μκ² λ©λλ€. κ·Έ μ΄νμ μμ μ μνν μν©μ΄ λλ©΄ notify()λ₯Ό νΈμΆνμ¬, μμ μ μ€λ¨νλ μ°λ λλ₯Ό κΉ¨μ λ€μ λ½μ μ»μ΄ μμ μ μ§νν μ μκ² ν©λλ€.
νμ§λ§ notify()λ₯Ό μ΄μ©νλ©΄ μ€λ κΈ°λ€λ¦° μ°λ λκ° λ½μ μ»λλ€λ 보μ₯μ μμ΅λλ€. wait()μ΄ νΈμΆλλ©΄ μ€ν μ€μ΄λ μ°λ λλ waiting poolμμ ν΅μ§λ₯Ό κΈ°λ€λ¦¬κ² λλλ°, notify()κ° νΈμΆλλ©΄ ν΄λΉ κ°μ²΄μ waiting poolμ€μ μμμ μ°λ λλ§ ν΅μ§λ₯Ό λ°κ² λ©λλ€. λ¬Όλ‘ notifyAll()μ μ΄μ©νλ©΄ λͺ¨λ μ°λ λλ₯Ό κΉ¨μΈ μ μμ§λ§ κ²°κ΅ λ½μ κ°μ²΄λΉ νλμ΄κΈ° λλ¬Έμ μμμ μ°λ λλ§ μ€νλκ³ λλ¨Έμ§ μ°λ λλ€μ λ€μ waiting poolμμ κΈ°λ€λ¦¬κ² λ©λλ€.
- κΈ°μ νμ
notify()λ₯Ό νμ©νλ©΄ μμμ λ§νλ―μ΄ μμμ μ°λ λλ§ κΉ¨μ΄λκ² λλ©°, μ΄μ©λ©΄ μ΅μ μ μν©μμ μνλ μ°λ λκ° λκΉμ§ κΉ¨μ΄λμ§ λͺ»νλ μνκ° μ¬μλ μμ΅λλ€. μ΄λ¬ν μν©μ κΈ°μ νμμ΄λΌκ³ ν©λλ€. μ΄ νμμ λ§μΌλ €λ©΄ notify() λμ notifyAll()μ νμ©ν΄μΌ ν©λλ€. νμ§λ§ notifyAll()λ λΆλͺ ν λ¬Έμ κ° μ‘΄μ¬ν©λλ€.
- κ²½μ μν
notifyAll()μ νμ©νλ©΄ λͺ¨λ μ°λ λλ₯Ό κΉ¨μΈ μ μμ§λ§, κ²°κ΅ κ°μ²΄λΉ λ½μ νλμ΄κΈ° λλ¬Έμ λ½ νλλ₯Ό λκ³ λͺ¨λ μ°λ λκ° μλ‘ κ²½μνκ² λ©λλ€. μ΄λ¬ν κ²μ κ²½μ μνλΌκ³ ν©λλ€. μ΄ κ²½μ μνλ₯Ό κ°μ νκΈ° μν΄μλ κ²°κ΅μ μμ μ΄ μνλ μ°λ λλ₯Ό μ§μ μ§λͺ νμ¬ ν΅μ§ν΄μΌ ν©λλ€.
Lock
λκΈ°νν μ μλ λ°©λ²μ synchronizedλΈλ μΈμλ 'java.util.concurrent.locks'ν¨ν€μ§κ° μ 곡νλ locksν΄λμ€λ€μ μ΄μ©νλ λ°©λ²μ΄ μμ΅λλ€. synchronizedλΈλμ μ¬μ©νκ² λλ©΄ μλμΌλ‘ lockμ΄ κ±Έλ¦¬κ³ ν리기 λλ¬Έμ κ΅μ₯ν νΈλ¦¬ν©λλ€. μ¬μ§μ΄ synchronizedλΈλ μμμμ μμΈκ° λ°μνλ€ν΄λ lockμ μλμ μΌλ‘ ν립λλ€. κ·Έλ¬λ λλ‘λ κ°μ λ©μλ λ΄μμλ§ lockμ κ±Έ μ μλ€λ μ μ½μ΄ λΆνΈνκΈ°λ ν©λλ€. λ°λΌμ μ΄λ° μ μ½μ΄ λ¬Έμ κ° λ λ lockν΄λμ€λ₯Ό μ¬μ©νκ² λ©λλ€.
lockν΄λμ€μ μ’ λ₯λ λ€μκ³Ό κ°μ΄ 3κ°μ§ μ’ λ₯κ° μμ΅λλ€.
- 1. ReentrantLock
ReentrantLockμ κ°μ₯ μΌλ°μ μΈ Lockμ λλ€. reentrant(μ¬μ§μ ν μ μλ)μ΄λΌλ λ¨μ΄κ° μμ λΆμ μ΄μ λ μμμ μΈκΈνλ wait(), notify() μ²λΌ νΉμ 쑰건μμ Lockμ νκ³ , λμ€μ λ€μ Lockμ μ»μ΄μ Critical SectionμΌλ‘ λ€μ΄μμ μ΄νμ μμ μ μνν μ μκΈ° λλ¬Έμ λλ€.
- ReentrantReadWriteLock
ReentrantReadWriteLockμ μ½κΈ°λ₯Ό μν Lockκ³Ό μ°κΈ°λ₯Ό μν Lockμ λ°λ‘ μ 곡ν©λλ€. ReentrantReadWriteLockμ μ½κΈ° Lockμ΄ κ±Έλ €μμΌλ©΄, λ€λ₯Έ μ°λ λκ° μ½κΈ° Lockμ μ€λ³΅ν΄μ κ±Έκ³ μ½κΈ°λ₯Ό μνν μ μμ΅λλ€. νμ§λ§ μ½κΈ° Lockμ΄ κ±Έλ¦° μνμμ μ°κΈ° Lockμ κ±°λ κ²μ νμ©νμ§ μμ΅λλ€. λν λ°λμ κ²½μ°λ λν λ§μ°¬κ°μ§ μ λλ€.
- StampedLock
StampedLockμ Lockμ κ±Έκ±°λ ν΄μ§ν λ 'μ€ν¬ν(longνμ μ μ μκ°)'μ μ¬μ©νλ©°, μ½κΈ°μ μ°κΈ°λ₯Ό μν lockμΈμ 'λκ΄μ μ½κΈ° lock'μ΄ μΆκ°λ κ²μ λλ€. λ§μ½ μ½κΈ° lockμ΄ κ±Έλ €μλ€λ©΄ μ°κΈ° lockμ κ±ΈκΈ° μν΄μλ μ½κΈ° lockμ΄ ν릴 λ κΉμ§ κΈ°λ€λ €μΌνλλ°μ λΉν΄ 'λκ΄μ μ½κΈ° lock'μ μ½κΈ° lockμ΄ κ±Έλ €μλ μνμμ μ°κΈ° lockμ 건λ€λ©΄, μ½κΈ° lockμ λ°λ‘ νλ¦¬κ² λ©λλ€. λ°λΌμ 무쑰건 μ½κΈ° lockμ κ±Έμ§ μκ³ , μ½κΈ° lockκ³Ό μ°κΈ° lockμ΄ μΆ©λν λλ§ μ°κΈ°κ° λλ νμ μ½κΈ° lockμ κ±Έμ΄μΌλ§ ν©λλ€.
Condition
μμμ wait()κ³Ό notify()λ₯Ό μ¬μ©νλ©΄ μμ μ΄ μνλ μ°λ λλ₯Ό μ§μ 골λΌμ ν΅μ§νμ§ λͺ»νλ€λ λ¨μ μ μΈκΈνμμ΅λλ€. Conditionμ μ΄ λ¬Έμ μ μ ν΄κ²°νκΈ° μν΄ κ³ μλ κ²μ λλ€. wait()κ³Ό notify()λ‘ κ³΅μ κ°μ²΄μ waiting poolμ κ°μ΄ λͺ°μλ£λ λμ , κ°κ° μ’ λ₯μ μ°λ λλ₯Ό μν Conditionμ λ§λ€μ΄μ κ°κ°μ waiting poolμμ λ°λ‘ κΈ°λ€λ¦¬λλ‘ νλ©΄ λ¬Έμ λ ν΄κ²°λ κ²μ λλ€. μ¦, λ§μ½μ μμμ μμ±νλ μλ¦¬μ¬ μ°λ λμ μμμ μλΉνλ μλ μ°λ λκ° μλ€κ³ ν΄λ΄ μλ€.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
public class ThreadRestaurant {
/* μλ΅ */
}
class Customer implements Runnable {
@Override
public void run() {
/* μλ΅ */
}
}
class Cook implements Runnable {
@Override
public void run() {
/* μλ΅ */
}
}
class Table {
String[] dishNames = {"donut", "donut", "burger"};
final int MAX_FOOD = 2; // μ΅λ 2κ°
private ArrayList<String> dishes = new ArrayList<>();
private ReentrantLock lock = new ReentrantLock(); //μΌλ°μ μΈ Lock
private Condition forCook = lock.newCondition(); //μ리μ¬μ© condition
private Condition forCus = lock.newCondition(); //μλμ© condition
public void add(String dish) {
lock.lock(); //λ½μ 건λ€.
try {
while(dishes.size() >= MAX_FOOD) { //μμμ λͺ»λ§λλ μν©
String name = Thread.currentThread().getName();
System.out.println(name + " is waiting");
try {forCook.await();Thread.sleep(500);} catch(InterruptedException e) {} //wait!
}
dishes.add(dish);
System.out.println("Dishes :" + dishes.toString());
} finally {
lock.unlock(); //μ΄λ€ μΌμ΄ μΌμ΄λλ lockμ λ°νν΄μΌν¨.
}
}
public void remove(String dishName) {
lock.lock(); //λ½μ 건λ€.
try {
while(dishes.size()==0) { //μμμ΄ μμΌλ©΄ λ¨Ήμ μ μλ€.
String name = Thread.currentThread().getName();
System.out.println(name+ " is waiting.");
try {forCus.await(); Thread.sleep(500);} catch(InterruptedException e) {} //wait!
}
for(int i=0; i<dishes.size(); i++) { //νΉμ μμμ μ κ±°
if(dishName.contentEquals(dishes.get(i))) {
return;
}
}
} finally {
}
}
public int dishNum() { return dishNames.length; }
}
|
μμ Table Class ꡬν λΆλΆμ 보면 κ°κ° μλμ© Conditionκ³Ό μ리μ¬μ© Conditionμ μ μΈνλ λΆλΆμ΄ μ‘΄μ¬ν©λλ€. μμ μμμ²λΌ ꡬλΆμ΄ νμν μ°λ λ λ³λ‘ Conditionμ μ μΈνμ¬ μ¬μ©νκ² λλ©΄ notify()μ wait()μ΄ λΆκ°λ₯νλ λΆλΆμ μμμνκ² ν΄κ²°ν μ μκ² λ©λλ€. μ°Έκ³ λ‘ Condition ν΄λμ€λ notify(), wait()μ΄ μλ signal(), await() μ λλ€.