πΉ 8. Thread & Lock
15. μ€λ λμ λ½
[ μλ°μ μ€λ λ ]
μλ°μ λͺ¨λ μ€λ λλ java.lang.Thread
ν΄λμ€ κ°μ²΄μ μν΄ μμ±λκ³ μ μ΄λλ€.
λ 립μ μΈ μμ© νλ‘κ·Έλ¨μ΄ μ€νλ λ, main() λ©μλλ₯Ό μ€ννκΈ° μν νλμ μ¬μ©μ μ€λ λ(user thread)κ° μλμΌλ‘ λ§λ€μ΄ μ§λλ°, μ΄ μ€λ λλ₯Ό μ£Ό μ€λ λ(main thread)λΌκ³ λΆλ₯Έλ€.
μλ°μμ μ€λ λλ₯Ό ꡬννλ λ°©λ² λ κ°μ§λ λ€μκ³Ό κ°λ€.
- java.lang.Runnable μΈν°νμ΄μ€λ₯Ό ꡬννκΈ°
- java.lang.Thread μΈν°νμ΄μ€λ₯Ό ꡬννκΈ°
Runnable μΈν°νμ΄μ€λ₯Ό ꡬννλ λ°©λ²
Runnable μΈν°νμ΄μ€λ λ¨μν ꡬ쑰λ₯Ό κ°μ§λ€.
1
2
3
public interface Runnable {
void run();
}
μ΄ μΈν°νμ΄μ€λ₯Ό μ¬μ©ν΄ μ€λ λλ₯Ό λ§λ€κ³ μ¬μ©νλ €λ©΄ λ€μμ κ³Όμ μ κ±°μ³μΌ νλ€.
- Runnable μΈν°νμ΄μ€λ₯Ό ꡬννλ ν΄λμ€λ₯Ό λ§λ λ€. μ΄ ν΄λμ€μ κ°μ²΄λ Runnable κ°μ²΄κ° λλ€.
Thread νμ μ κ°μ²΄λ₯Ό λ§λ€ λ, Threadμ μμ±μμ Runnable κ°μ²΄λ₯Ό μΈμλ‘ λκΈ΄λ€.
μ΄ Thread κ°μ²΄λ μ΄μ run() λ©μλλ₯Ό ꡬννλ Runnable κ°μ²΄λ₯Ό μμ νκ² λλ€.
- μ΄μ λ¨κ³μμ μμ±ν Thread κ°μ²΄μ start() λ©μλλ₯Ό νΈμΆνλ€.
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
// 1λ² μν(Runnable μΈν°νμ΄μ€ ꡬν)
public class RunnableThreadExample implements Runnable {
public int count = 0;
public void run() {
System.out.println("RunnableThread starting");
try {
while (count < 5) {
Thread.sleep(500);
count++;
}
} catch (InterruptedExceptiono exc) {
System.out.println("RunnableThread interrupted.");
}
System.out.println("RunnableThread terminating.");
}
}
public static void main(String[] args) {
RunnableThreadExample instance = new RunnableThreadExample();
Thread thread = new Thread(instance); // 2λ² μν
thread.start(); // 3λ² μν
/* μ€λ λ κ°μκ° 5κ°κ° λ λκΉμ§ μ²μ²ν κΈ°λ€λ¦°λ€. */
while (instance.count != 5) {
try {
Thread.sleep(250);
} catch (InterruptedException exc) {
exc.printStackTrace();
}
}
}
μ μ½λμμ μ€μ λ‘ ν΄μΌνλ μΌμ run() λ©μλλ₯Ό ꡬννλ κ² λΏμ΄λ€. κ·Έλ¬λ©΄ main λ©μλλ ν΄λΉ ν΄λμ€μ μΈμ€ν΄μ€(instance)λ₯Ό new Thread(obj)μ μΈμλ‘ λκΈ°κ³ start()λ₯Ό νΈμΆνλ€.
Thread ν΄λμ€ μμ
Runnable μ΄μΈμ Thread ν΄λμ€λ₯Ό μμλ°μμ μ€λ λλ₯Ό λ§λ€ μλ μλ€. κ·Έλ¬λ €λ©΄ κ±°μ νμ run() λ©μλλ₯Ό μ€λ²λΌμ΄λ(override)ν΄μΌ νλ©°, νμ ν΄λμ€μ μμ±μλ μμ ν΄λμ€μ μμ±μλ₯Ό λͺ μμ μΌλ‘ νΈμΆν΄μΌ νλ€.
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
/* μ€λ λ μμ */
public class ThreadExample extends Thread {
int count = 0;
public void run() {
System.out.println("Thread starting");
try {
while (count < 5) {
Thread.sleep(500);
System.out.println("In Thread, count is " + count);
count++;
}
} catch (InterruptedException exc) {
System.out.println("Thread interrupted.");
}
System.out.println("Thread terminating");
}
}
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();
}
}
}
}
Runnable μΈν°νμ΄μ€ ꡬνκ³Ό λ€λ₯Έ μ μ μΈν°νμ΄μ€λ₯Ό ꡬννλ λμ Thread ν΄λμ€λ₯Ό μμλ°μκ³ , λ°λΌμ μΈμ€ν΄μ€ μ체μμ start()λ₯Ό μ§μ νΈμΆνκ² λλ€.
Thread μμ vs Runnable μΈν°νμ΄μ€ ꡬν
μ€λ λλ₯΄ μμ±ν λ Runnable μΈν°νμ΄μ€λ₯Ό ꡬννλ κ²μ΄ Threadλ₯Ό μμλ°λ κ²λ³΄λ€ μ νΈλλ μ΄μ κ° λ κ°μ§ μ‘΄μ¬νλ€.
- μλ°λ λ€μ€ μμ(multiple inheritance)λ₯Ό μ§μνμ§ μλλ€. λ°λΌμ Thread ν΄λμ€λ₯Ό μμνκ² λλ©΄ νμ ν΄λμ€λ λ€λ₯Έ ν΄λμ€λ₯Ό μμν μκ° μλ€. νμ§λ§ Runnable μΈν°νμ΄μ€λ₯Ό ꡬννλ ν΄λμ€λ λ€λ₯Έ ν΄λμ€λ₯Ό μμν μ μλ€.
- Thread ν΄λμ€μ λͺ¨λ κ²μ μμλ°λ κ²μ΄ λ무 λΆλ΄λλ κ²½μ°μλ Runnableμ ꡬννλ νΈμ΄ λμμ§λ λͺ¨λ₯Έλ€.
[ λκΈ°νμ λ½ ]
ν νλ‘μΈμ€ μμμ μμ±λ μ€λ λλ€μ κ°μ λ©λͺ¨λ¦¬ 곡κ°μ 곡μ νλ€. μ€λ λκ° μλ‘ λ°μ΄ν°λ₯Ό 곡μ ν μ μλ€λ μ μ μ₯μ μ΄κΈ΄ νμ§λ§ λ μ€λ λκ° κ°μ μμμ λμμ λ³κ²½νλ κ²½μ°μλ λ¬Έμ κ° λλ€.
μλ°λ 곡μ μμμ λν μ κ·Όμ μ μ΄νκΈ° μν λκΈ°ν(synchronization) λ°©λ²μ μ 곡νλ€.
synchronizedμ Lockμ΄λΌλ ν€μλλ λκΈ°ν ꡬνμ μν κΈ°λ³Έμ΄ λλ€.
λκΈ°νλ λ©μλ
ν΅μμ μΌλ‘ synchronized ν€μλλ₯Ό μ¬μ©ν λλ 곡μ μμμ λν μ κ·Όμ μ μ΄νλ€.
μ΄ ν€μλλ λ©μλμ μ μ©ν μλ μκ³ , νΉμ ν μ½λ λΈλ‘μ μ μ©ν μλ μλ€. λν μ¬λ¬ μ€λ λκ° κ°μ κ°μ²΄λ₯Ό λμμ μ€ννλ κ² λν λ°©μ§ν΄μ£Όμ€λ€.
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
public class MyClass extends Thread {
private String name;
private MyObject myObj;
public MyClass(MyObject obj, String n) {
name = n;
myObj = obj;
}
public void run() {
myObj.foo(name);
}
}
public class MyObject {
public **synchronized** void foo(String name) {
try {
System.out.println("Thread" + name + ".foo(): starting");
Thread.sleep(3000);
System.out.println("Thread" + name + ".foo(): ending");
} catch (InterruptedException exc) {
System.out.println("Thread" + name + ": interrupted.");
}
}
}
λ κ°μ MyClass μΈμ€ν΄μ€κ° fooλ₯Ό λμμ νΈμΆν μ μμκΉ? μν©μ λ°λΌ λ€λ₯΄λ€.
κ°μ MyObject μΈμ€ν΄μ€λ₯Ό κ°λ¦¬ν€κ³ μλ€λ©΄ λμ νΈμΆμ λΆκ°λ₯νμ§λ§ λ€λ₯Έ μΈμ€ν΄μ€λ₯Ό κ°λ¦¬ν€κ³ μλ€λ©΄ κ°λ₯νλ€.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* μλ‘ λ€λ₯Έ κ°μ²΄μΈ κ²½μ° λμμ MyObject.foo() νΈμΆμ΄ κ°λ₯νλ€. */
MyObject obj1 = new MyObject();
MyObject obj2 = new MyObject();
MyClass thread1 = new MyClass(obj1, "1");
MyClass thread2 = new MyClass(obj2, "2");
thread1.start();
thread2.start();
/* κ°μ objλ₯Ό κ°λ¦¬ν€κ³ μλ κ²½μ°μλ νλλ§ fooλ₯Ό νΈμΆν μ μκ³ ,
* λ€λ₯Έ νλλ κΈ°λ€λ¦¬κ³ μμ΄μΌ νλ€. */
MyObject obj = new MyObject();
MyClass thread1 = new MyClass(obj, "1");
MyClass thread2 = new MyClass(obj, "2");
thread1.start();
thread2.start();
μ μ λ©μλ(static method)λ ν΄λμ€ λ½(class lock)μ μν΄ λκΈ°ν λλ€. κ°μ ν΄λμ€μ μλ λκΈ°νλ μ μ λ©μλλ λ μ€λ λμμ λμμ μ€νλ μ μλ€. μ€μ¬ νλλ fooλ₯Ό νΈμΆνκ³ λ€λ₯Έ νλλ barλ₯Ό νΈμΆνλ€κ³ ν΄λ λ§μ΄λ€.
1
2
3
4
5
6
7
8
9
10
11
12
public class MyClass extends Thread {
...
public void run() {
if (name.equals("1")) MyObject.foo(name);
else if (name.equals("2")) MyObject.bar(name);
}
}
public class MyObject {
public static synchronized void foo(String name) { /* ... */ }
public static synchronized void bar(String name) { /* ... */ }
}
μ΄ μ½λλ₯Ό μ€ννμ λ μΆλ ₯λλ κ²°κ³Όλ λ€μκ³Ό κ°λ€.
1
2
3
4
Thread 1.foo(): starting
Thread 1.foo(): ending
Thread 2.bar(): starting
Thread 2.bar(): ending
λκΈ°νλ λΈλ‘
μ΄μ λΉμ·νκ², νΉμ ν μ½λ λΈλ‘μ λκΈ°νν μλ μλ€. μ΄λ λ©μλλ₯Ό λκΈ°ννλ κ²κ³Ό μμ£Ό λΉμ·νκ² λμνλ€.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MyClass extends Thread {
...
public void run() {
myObj.foo(name);
}
}
public class MyObject {
public void foo(String name) {
**synchronized**(this) {
...
}
}
}
λ©μλλ₯Ό λκΈ°ννλ κ²κ³Ό λ§μ°¬κ°μ§λ‘, MyObject μΈμ€ν΄μ€ νλλΉ νλμ μ€λ λ λ§μ΄ synchronized λΈλ‘ μμ μ½λλ₯Ό μ€νν μ μλ€. λ€μ λ§ν΄ thread1κ³Ό thread2κ° λμΌν MyObject μΈμ€ν΄μ€λ₯Ό κ°κ³ μλ€λ©΄, κ·Έ κ°μ΄λ° νλλ§ κ·Έ μ½λ λΈλ‘μ μ€νν μ μλ€.
λ½
μ’ λ μΈλ°νκ² λκΈ°νλ₯Ό μ μ΄νκ³ μΆμ λλ λ½(lock)μ μ¬μ©νλ€. λ½(λͺ¨λν°(monitor)λΌκ³ λ νλ€)μ 곡μ μμμ λΆμ΄λ©΄ ν΄λΉ μμμ λν μ κ·Όμ λκΈ°νν μ μλ€.
μ€λ λκ° ν΄λΉ μμμ μ κ·Όνλ €λ©΄ μ°μ κ·Έ μμμ λΆμ΄ μλ λ½μ νλν΄μΌ νλ€. νΉμ μμ μ λ½μ μ₯κ³ μμ μ μλ μ€λ λλ νλλΏμ΄λ€. λ°λΌμ ν΄λΉ 곡μ μμμ ν λ²μ ν μ€λ λλ§μ΄ μ¬μ©ν μ μλ€.
μ΄λ€ μμμ΄ νλ‘κ·Έλ¨ λ΄μ μ΄κ³³μ κ³³μμ μ¬μ©λμ§λ§ ν λ²μ ν μ€λ λλ§ μ¬μ©νλλ‘ λ§λ€κ³ μ ν λ μ£Όλ‘ λ½μ μ΄μ©νλ€.
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
public class LockedATM {
private Lock lock;
private int balance = 100;
public LockedATM() {
lock = new ReentrantLock();
}
public int withdraw(int value) {
lock.lock();
int temp = balance;
try {
Thread.sleep(100);
temp = temp - value;
Thread.sleep(100);
balance = temp;
} catch (InterruptedExceptino e) {
lock.unlock();
return temp;
}
public int deposit(int value) {
lock.lock();
int temp = balancee;
try {
Thread.sleep(100);
temp = temp + value;
Thread.sleep(300);
balance = temp;
} catch (InterruptedException e) { }
lock.unlock();
return temp;
}
}
λ½μ μ¬μ©νλ©΄ 곡μ λ μμμ΄ μκΈ°μΉ μκ² λ³κ²½λλ μΌμ λ§μ μ μλ€.
(Thread.sleepμ λ°μ κ°λ₯ν λ¬Έμ μ μ 보μ΄κΈ° μν΄ μΌλΆλ¬ λλ¦¬κ² λ§λ κ² - μ¬μ© μν΄λλ¨)
[ κ΅μ°©μνμ κ΅μ°©μν λ°©μ§ ]
- κ΅μ°©μν(deadlock)
첫 λ²μ§Έ μ€λ λλ λ λ²μ§Έ μ€λ λκ° λ€κ³ μλ κ°μ²΄μ λ½μ΄ ν리기λ₯Ό κΈ°λ€λ¦¬κ³ μκ³ , λ λ²μ§Έ μ€λ λ μμ 첫 λ²μ§Έ μ€λ λκ° λ€κ³ μλ κ°μ²΄μ λ½μ΄ ν리기λ₯Ό κΈ°λ€λ¦¬λ μν©(μ¬λ¬ μ€λ λκ° κ΄κ³λμ΄ μμ λ λ°μν μ μλ€.)
λͺ¨λ μ€λ λκ° λ½μ΄ ν리기λ₯Ό κΈ°λ€λ¦¬κ³ μκΈ° λλ¬Έμ, 무ν λκΈ° μνμ λΉ μ§κ² λλ€.
κ΅μ°© μνκ° λ°μνλ €λ©΄, λ€μμ λ€ κ°μ§ μ‘°κ±΄μ΄ λͺ¨λ μΆ©μ‘±λμ΄μΌ νλ€.
μνΈ λ°°μ (mutual exclusion)
: ν λ²μ ν νλ‘μΈμ€λ§ 곡μ μμμ μ¬μ©ν μ μλ€.(μ’ λ μ νν μ΄μΌκΈ°νμλ©΄, 곡μ μμμ λν μ κ·Ό κΆνμ΄ μ νλλ€. μμ°λμ μμ΄ μ νλμ΄ μλλΌλ(ν κ° μ΄μ) κ΅μ°©μνλ λ°μν μ μλ€.)
λ€κ³ κΈ°λ€λ¦¬κΈ°(hold and wait)
: 곡μ μμμ λν μ κ·Ό κΆνμ κ°κ³ μλ νλ‘μΈμ€κ°, κ·Έ μ κ·Ό κΆνμ μ보νμ§ μμ μνμμ λ€λ₯Έ μμμ λν μ κ·Ό κΆνμ μꡬν μ μλ€.
μ μ·¨(preemption) λΆκ°λ₯
: ν νλ‘μΈμ€κ° λ€λ₯Έ νλ‘μΈμ€μ μμ μ κ·Ό κΆνμ κ°μ λ‘ μ·¨μν μ μλ€.
λκΈ° μνμ μ¬μ΄ν΄(circular wait)
: λ κ° μ΄μμ νλ‘μΈμ€κ° μμ μ κ·Όμ κΈ°λ€λ¦¬λλ°, κ·Έ κ΄κ³μ μ¬μ΄ν΄(cycle)μ΄ μ‘΄μ¬νλ€.
κ΅μ°© μνλ₯Ό λ°©μ§νκΈ° μν΄μ μ μ‘°κ±΄λ€ μ€ νλλ₯Ό μ κ±°νλ©΄ λλ€. νμ§λ§ μ΄λ€ 쑰건 κ°μ΄λ° μλΉμλ λ§μ‘±λκΈ° μ΄λ €μ΄ κ²μ΄λΌ κΉλ€λ‘λλ€.
곡μ μμ μ€ λ§μ κ²½μ°κ° ν λ²μ ν νλ‘μΈμ€λ§ μ¬μ©ν μ μκΈ° λλ¬Έμ(ex. νλ¦°ν°) 1λ² μ‘°κ±΄μ μ κ±°νκΈ° μ΄λ ΅λ€. λλΆλΆμ κ΅μ°©μν λ°©μ§ μκ³ λ¦¬μ¦μ 4λ² μ‘°κ±΄, μ¦ λκΈ° μνμ μ¬μ΄ν΄μ΄ λ°μνλ μΌμ λ§λ λ° μ΄μ μ΄ λ§μΆ°μ Έ μλ€.