多线程活跃性——哲学家就餐问题及死锁

死锁是多线程编程中最常见的一种"活跃性问题",除了死锁还包括"饥饿"和"活锁",这些活跃性问题给并发编程带来极大的挑战。比如出现死锁时,定位和分析问题相对困难,一旦出现死锁,通常只能重启应用程序。本文通过死锁最经典的"哲学家就餐问题"来介绍死锁的产生原因和解决办法。 1. 死锁 死锁指的是多个线程相互等待彼此而进入永久暂停状态。比如,线程 T1 持有锁 L1 去申请锁 L2,但是线程 T2 持有锁 L2 申请锁 L1,此时它们都在等待对象释放锁,从而进入永久阻塞状态。这就好比两个小朋友,他们各有一个玩具,但都不愿意分享给对方,却希望获得对方的玩具,最终互不相让,只能彼此干瞪眼了。 写一个死锁的程序很简单,比如下边的代码: public class DeadLockTest { private static final Object lock1 = new Object(); private static final Object lock2 = new Object(); public static void main(String[] args) { new Thread(new MyThread1(lock1, lock2)).start(); new Thread(new MyThread2(lock1, lock2)).start(); } } class MyThread1 implements Runnable { private final Object lock1; private final Object lock2; public MyThread1(Object lock1, Object lock2) { this.lock1 = lock1; this.lock2 = lock2; } @Override public void run() { while (true) { synchronized (lock1) { (1) System.out.println("using lock1"); synchronized (lock2) { System.out.println("using lock2"); } } } } } class MyThread2 implements Runnable { private final Object lock1; private final Object lock2; public MyThread2(Object lock1, Object lock2) { this.lock1 = lock1; this.lock2 = lock2; } @Override public void run() { while (true) { synchronized (lock2) { (2) System.out.println("using lock2"); synchronized (lock1) { System.out.println("using lock1"); } } } } } ...

2022-01-20 · 6 min · 1208 words · Hank