π¦ 8. Thread & Lock
μλ°μ μ€λ λ
μλ°μ λͺ¨λ μ€λ λλ java.lang.Thread
ν΄λμ€ κ°μ²΄μ μν΄ μμ±λκ³ μ μ΄λλ€.
μλ°μμ μ€λ λλ₯Ό ꡬννλ λ°©λ²μ λ κ°μ§κ° μλ€.
java.lang.Runnable
μΈν°νμ΄μ€λ₯Ό ꡬννκΈ°java.lang.Thread
ν΄λμ€λ₯Ό μμλ°κΈ°
Runnable μΈν°νμ΄μ€λ₯Ό ꡬννλ λ°©λ²
1
2
3
public interface Runnable {
void run();
}
- Runnable μΈν°νμ΄μ€λ₯Ό ꡬννλ ν΄λμ€λ₯Ό λ§λ λ€
- Thread νμ μ κ°μ²΄ μμ±μμ Runnable κ°μ²΄λ₯Ό μΈμλ‘ λκΈ΄λ€
- Thread κ°μ²΄μ start() λ©μλλ₯Ό νΈμΆνλ€
1
2
3
4
5
6
7
8
9
10
11
12
13
public static void main(String[] args) {
RunnableThreadExample instance = new RunnableThreadExample();
Thread thread = new Thread(instance);
thread.start();
while (instance.count != 5) {
try {
Thread.sleep(25);
} catch (InterruptedException exc) {
exc.printStackTrace();
}
}
}
Thread ν΄λμ€ μμ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class ThreadExample extends Thread {
int count = 0;
public void run() {
...
}
}
public class ExampleB {
public static void main(String args[]) {
ThreadExample instance = new ThreadExample();
instance.start();
while (instance.count != 5) {
try {
Thread.sleep(250);
} catch (InterruptedException exc) {
exc.printStackTrace();
}
}
}
}
μΈν°νμ΄μ€λ₯Ό ꡬννλ λμ Thread ν΄λμ€λ₯Ό μμλ°μ μΈμ€ν΄μ€ννκ³ start() λ₯Ό μ§μ νΈμΆνκ² λλ€.
Thread μμ vs. Runnable μΈν°νμ΄μ€ ꡬν
μ€λ λλ₯Ό μμ±ν λ Runnable μΈν°νμ΄μ€λ₯Ό ꡬννλ κ²μ΄ λ μ νΈλλ€.
- μλ°λ λ€μ€ μμμ μ§μνμ§ μκΈ° λλ¬Έμ, Thread λ₯Ό μμνκ² λλ©΄ νμ ν΄λμ€λ λ€λ₯Έ ν΄λμ€λ₯Ό μμν μ μλ€. λ°λ§ Runnable μΈν°νμ΄μ€λ₯Ό ꡬννλ ν΄λμ€λ λ€λ₯Έ ν΄λμ€λ₯Ό μμλ°μ μ μλ€.
- Thread ν΄λμ€μ λͺ¨λ κ²μ μμλ°λ κ²μ΄ λ무 λΆλ΄μ€λ¬μ΄ κ²½μ°μ Runnable μ ꡬννλ νΈμ΄ λ«λ€.
λκΈ°νμ λ½
μ΄λ€ νλ‘μΈμ€ μμμ μμ±λ μ€λ λλ€μ κ°μ λ©λͺ¨λ¦¬ 곡κ°μ 곡μ νλ€.
λ μ€λ λκ° κ°μ μμμ λμμ λ³κ²½νλ κ²½μ°μλ λ¬Έμ κ° λλ€.
μλ°λ 곡μ μμμ λν μ κ·Όμ μ μ΄νκΈ° μν λκΈ°ν λ°©λ²μ μ 곡νλ€.
λκΈ°νλ λ©μλ
synchronized
ν€μλλ₯Ό μ¬μ©ν λ 곡μ μμμ λν μ κ·Όμ μ μ΄νλ€.
λ©μλ λλ νΉμ μ½λ λΈλ‘μ μ μ©ν μ μλ€.
1
2
3
4
5
public class MyObject {
public synchronized void foo(String name) {
...
}
}
λ κ°μ MyClass μΈμ€ν΄μ€κ° foo λ₯Ό λμμ νΈμΆν μ μμκΉ?
κ°μ MyObject μΈμ€ν΄μ€λ₯Ό κ°λ¦¬ν€κ³ μλ€λ©΄ λμ νΈμΆμ΄ λΆκ°λ₯νλ€.
λ€λ₯Έ μΈμ€ν΄μ€λ₯Ό κ°μ§κ³ μλ€λ©΄ κ°λ₯νλ€.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
MyObject obj1 = new MyObject();
MyObject obj1 = new MyObject();
MyClass thread1 = new MyClass(obj1, "1");
MyClass thread1 = new MyClass(obj2, "2");
thread1.start();
thread2.start();
// λμ νΈμΆ OK
MyObject obj = new MyObject();
MyClass thread1 = new MyClass(obj, "1");
MyClass thread1 = new MyClass(obj, "2");
thread1.start();
thread2.start();
// λμ νΈμΆ X, λ€λ₯Έ νλλ κΈ°λ€λ¦¬κ³ μμ΄μΌ νλ€.
μ μ λ©μλλ ν΄λμ€ λ½μ μν΄ λκΈ°νλλ€.
κ°μ ν΄λμ€μ μλ λκΈ°νλ μ μ λ©μλλ λ μ€λ λμμ λμμ μ€νλ μ μλ€.
νλλ foo λ₯Ό νΈμΆνκ³ , λ€λ₯Έ νλλ barμ νΈμΆνλ€κ³ ν΄λ λ§μ΄λ€.
1
2
3
4
5
6
7
8
9
10
11
12
public class MyClass extends Thread {
...
public void run() {
if (name.equlas("1")) MyObject.foo(name);
else if (name.equals("2")) MyObject.bar(name);
}
}
public class MyObejct {
public static synchronized void foo(String name) { ... }
public static synchronized void bar(String name) { ... }
}
1
2
3
4
5
6
7
8
// μ€νκ²°κ³Ό
Thread 1.foo(): starting
Thread 1.bar(): ending
Thread 2.foo(): starting
Thread 2.bar(): ending
λκΈ°νλ λΈλ‘
νΉμ ν μ½λ λΈλ‘μ λκΈ°νν μ μλ€. μ΄λ λ©μλλ₯Ό λκΈ°ννλ κ²κ³Ό μμ£Ό λΉμ·νκ² λμνλ€.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class MyClass extends Thread {
...
public void run() {
myObj.foo(name);
}
}
public class MyObject {
...
public void foo(String name) {
synchronized(this) {
...
}
}
}
MyObject μΈμ€ν΄μ€ νλλΉ νλμ μ€λ λλ§μ΄ synchronized λΈλ‘ μμ μ½λλ₯Ό μ€νν μ μλ€.
λ½
μ’ λ μΈλ°νκ² λκΈ°νλ₯Ό μ μ΄νκ³ μΆλ€λ©΄ λ½(Lock)μ μ¬μ©νλ€.
λ½(λλ Monitor)μ 곡μ μμμ λΆμ΄λ©΄ ν΄λΉ μμμ λν μ κ·Όμ λκΈ°νν μ μλ€.
μ€λ λκ° ν΄λΉ μμμ μ κ·Όνλ €λ©΄ κ·Έ μμμ λΆμ΄μλ λ½μ νλν΄μΌ νλ€.
μ΄λ€ μμμ΄ νλ‘κ·Έλ¨ λ΄μ μ΄κ³³μ κ³³μμ μ¬μ©λμ§λ§ ν λ²μ ν μ€λ λλ§ μ¬μ©νλλ‘ λ§λ€κ³ μ ν λ μ£Όλ‘ λ½μ μ΄μ©νλ€.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class LockedATM {
private Lock lock;
private int balance = 100;
public LockedATM() {
lock = new ReentrantLock();
}
public int withdraw(int value) {
lock.lock();
...
lock.unlock();
return value;
}
public int deposit(int value) {
lock.lock();
...
lock.unlock();
return value;
}
}
λ½μ μ¬μ©νλ©΄ 곡μ λ μμμ΄ μκΈ°μΉ μκ² λ³κ²½λλ μΌμ λ§μ μ μλ€.
κ΅μ°©μνμ κ΅μ°©μν λ°©μ§
κ΅μ°©μν(deadlock)λ, μ€λ λ1μ μ€λ λ2κ° λ€κ³ μλ κ°μ²΄μ λ½μ΄ ν리기λ₯Ό κΈ°λ€λ¦¬κ³ μκ³ μ€λ λ2λ μ€λ λ1μ΄ λ€κ³ μλ κ°μ²΄μ λ½μ΄ ν리기λ₯Ό κΈ°λ€λ¦¬λ μν©μ΄λ€.
λͺ¨λ μ€λ λκ° λ½μ΄ ν리기λ₯Ό κΈ°λ€λ¦¬κ³ μκΈ° λλ¬Έμ 무ν λκΈ° μνμ λΉ μ§λ€.
κ΅μ°©μνκ° λ°μνλ €λ©΄ 4κ°μ§ 쑰건μ λͺ¨λ μΆ©μ‘±λμ΄μΌ νλ€.
- μνΈλ°°μ (mutual exclusion): ν λ²μ ν νλ‘μΈμ€λ§ 곡μ μμμ μ¬μ©ν μ μλ€.
- λ€κ³ κΈ°λ€λ¦¬κΈ°(hold and wait): 곡μ μμμ λν μ κ·Ό κΆνμ κ°μ§ νλ‘μΈμ€κ° μ κ·Ό κΆνμ μ보νμ§ μμ μνμμ λ€λ₯Έ μμμ λν μ κ·Ό κΆνμ μꡬν μ μλ€.
- μ μ·¨ λΆκ°λ₯(preemption): ν νλ‘μΈμ€κ° λ€λ₯Έ νλ‘μΈμ€μ μμ μ κ·Ό κΆνμ κ°μ λ‘ μ·¨μν μ μλ€.
- λκΈ° μνμ μ¬μ΄ν΄(circular wait): λ κ° μ΄μμ νλ‘μΈμ€κ° μμ μ κ·Όμ κΈ°λ€λ¦¬λλ°, κ·Έ κ΄κ³μ μ¬μ΄ν΄μ΄ μ‘΄μ¬νλ€.
κ΅μ°©μνλ₯Ό λ°©μ§νκΈ° μν΄ μ΄ μ‘°κ±΄ κ°μ΄λ° νλλ₯Ό μ κ±°νλ©΄ λλ€.
λλΆλΆμ κ΅μ°©μν λ°©μ§ μκ³ λ¦¬μ¦μ 4λ² μ‘°κ±΄μ λ§λλ° μ΄μ μ΄ λ§μΆ°μ Έμλ€.