๋ฉํฐ์ค๋ ๋ ํ๋ก๊ทธ๋๋ฐ์ ํ๋ค ๋ณด๋ฉด ์์ฃผ ์ ํ๊ฒ ๋๋ ๋ฌธ์ ๊ฐ ๋ฐ๋ก ๊ต์ฐฉ ์ํ(Deadlock)์ ๋๋ค. ์ต๊ทผ ์ ํ๋ฆฌ์ผ์ ์์ Deadlock์ด ๋ฐ์ํ๋ฉด์ ์ฅ์ ๊ฐ ๋ฐ์ํ์๊ณ ์ค๋ ๋ ๊ฐ ์์ ๊ณต์ ๋ฅผ ๊ด๋ฆฌํ๋ค๊ฐ ๊ต์ฐฉ ์ํ๋ฅผ ์๋ฐฉํ๋ ๋ฐฉ๋ฒ์ ๋ํด ๋ค์ ๊ณ ๋ฏผํ๊ฒ ๋์๋๋ฐ์. ์ด๋ฒ ๊ธ์์๋ ๊ต์ฐฉ ์ํ์ ๊ฐ๋ , ๋ฐ์ ์กฐ๊ฑด, ๊ทธ๋ฆฌ๊ณ ์๋ฐ์์ ์ด๋ฅผ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ์ ๋ฆฌํด ๋ณด์์ต๋๋ค.

๊ต์ฐฉ ์ํ(Deadlock)๋ ๋ ๊ฐ ์ด์์ ์์ ์ด ์๋ก ์๋๋ฐฉ์ ์์ ์ด ๋๋๊ธฐ๋ง์ ๊ธฐ๋ค๋ฆฌ๋ ์ํฉ์ ์๋ฏธํฉ๋๋ค. ์ด๋ก ์ธํด ํ๋ก์ธ์ค๋ค์ด ์๋ฌด ์์ ๋ ์๋ฃํ์ง ๋ชปํ๋ ์ํ์ ๋น ์ง๊ฒ ๋ฉ๋๋ค.
๊ต์ฐฉ ์ํ๋ ๋ค์ ๋ค ๊ฐ์ง ์กฐ๊ฑด์ด ๋์์ ๋ง์กฑ๋ ๋ ๋ฐ์ํฉ๋๋ค:
์ด ๋ค ๊ฐ์ง ์กฐ๊ฑด์ด ๋์์ ์ถฉ์กฑ๋ ๊ฒฝ์ฐ ๊ต์ฐฉ ์ํ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
์๋ฐ์์๋ synchronized ํค์๋๋ ReentrantLock์ ์ฌ์ฉํ์ฌ ์ค๋ ๋ ๋๊ธฐํ๋ฅผ ๊ตฌํํฉ๋๋ค. ํ์ง๋ง ์๋ชป๋ ์์ ํ ๋น ์์๋ก ์ธํด ๊ต์ฐฉ ์ํ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
public class DeadlockExample {
private static final Object resource1 = new Object();
private static final Object resource2 = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (resource1) {
System.out.println("Thread 1: Locked resource 1");
try { Thread.sleep(50); } catch (InterruptedException e) {}
synchronized (resource2) {
System.out.println("Thread 1: Locked resource 2");
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (resource2) {
System.out.println("Thread 2: Locked resource 2");
try { Thread.sleep(50); } catch (InterruptedException e) {}
synchronized (resource1) {
System.out.println("Thread 2: Locked resource 1");
}
}
});
thread1.start();
thread2.start();
}
}
์ ์ฝ๋์์๋ ์ค๋ ๋ 1๊ณผ ์ค๋ ๋ 2๊ฐ ์๋ก ์์์ ์ ๊ทธ๊ณ ๋๊ธฐํ๋ฉด์ ๊ต์ฐฉ ์ํ์ ๋น ์ง๊ฒ ๋ฉ๋๋ค.
๋ชจ๋ ์ค๋ ๋๊ฐ ์์์ ์ผ์ ํ ์์๋ก ์์ฒญํ๋๋ก ๊ท์น์ ์ ํ๋ฉด ์ํ ๋๊ธฐ ์กฐ๊ฑด์ ํผํ ์ ์์ต๋๋ค.
synchronized (resource1) {
synchronized (resource2) {
// ์์
์ํ
}
}
synchronized (resource1) {
synchronized (resource2) {
// ๋์ผํ ์์๋ก ์์ ์์ฒญ
}
}
ReentrantLock์ tryLock() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ์ผ์ ์๊ฐ ๋์๋ง ์์์ ๊ธฐ๋ค๋ฆฌ๋๋ก ์ค์ ํฉ๋๋ค.
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.TimeUnit;
public class DeadlockResolution {
private static final Lock lock1 = new ReentrantLock();
private static final Lock lock2 = new ReentrantLock();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
try {
if (lock1.tryLock(1, TimeUnit.SECONDS)) {
try {
System.out.println("Thread 1: Locked lock1");
Thread.sleep(50);
if (lock2.tryLock(1, TimeUnit.SECONDS)) {
try {
System.out.println("Thread 1: Locked lock2");
} finally {
lock2.unlock();
}
}
} finally {
lock1.unlock();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread thread2 = new Thread(() -> {
try {
if (lock2.tryLock(1, TimeUnit.SECONDS)) {
try {
System.out.println("Thread 2: Locked lock2");
Thread.sleep(50);
if (lock1.tryLock(1, TimeUnit.SECONDS)) {
try {
System.out.println("Thread 2: Locked lock1");
} finally {
lock1.unlock();
}
}
} finally {
lock2.unlock();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread1.start();
thread2.start();
}
}
์์์ ์ป์ง ๋ชปํ๋ฉด ์ผ์ ์๊ฐ ํ์ ํฌ๊ธฐํ๊ณ ๋์ค์ ๋ค์ ์๋ํ๋๋ก ์ค๊ณํฉ๋๋ค.
๊ต์ฐฉ ์ํ๋ ๋ฉํฐ์ค๋ ๋ ํ๋ก๊ทธ๋๋ฐ์์ ๋ฐ์ํ ์ ์๋ ์ฃผ์ ๋ฌธ์ ์ค ํ๋์ ๋๋ค. ๋ฐ์ ์กฐ๊ฑด์ ์ดํดํ๊ณ , ์ฌ๋ฐ๋ฅธ ์ฝ๋ฉ ์ต๊ด๊ณผ ๋๊ธฐํ ๋ฉ์ปค๋์ฆ์ ์ฌ์ฉํ๋ค๋ฉด ๊ต์ฐฉ ์ํ๋ฅผ ์๋ฐฉํ ์ ์์ต๋๋ค. ํ๋ก์ ํธ์์ ์ค๋ ๋ ๊ฐ ์์ ๊ณต์ ๋ฅผ ๊ด๋ฆฌํ ๋ ์ด๋ฌํ ๊ฐ๋ ์ ์ผ๋์ ๋์ด ์์ ์ ์ด๊ณ ํจ์จ์ ์ธ ์ฝ๋๋ฅผ ์์ฑํด๋ณด์์ฃ ๐