Post

🦊 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번 쑰건을 λ§‰λŠ”λ° 초점이 λ§žμΆ°μ Έμžˆλ‹€.

This post is licensed under CC BY 4.0 by the author.