1 死锁定义
所谓死锁是指两个或两个以上的线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。死锁是多线程程序设计带来的负面效果,在程序设计时需要防止死锁的发生。
2 死锁的必要条件
(1) 互斥条件:进程要求对所分配的资源(如打印机)进行排他性控制,即在一段时间内某资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。
(2) 不剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能由获得该资源的进程自己来释放(只能是主动释放)。
(3) 请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
(4) 循环等待条件:存在一种进程资源的循环等待链,链中每一个进程已获得的资源同时被链中下一个进程所请求。即存在一个处于等待状态的进程集合{Pl, P2, ..., pn},其中Pi等 待的资源被P(i+1)占有(i=0, 1, ..., n-1),Pn等待的资源被P0占有,如图1所示。
3 死锁实例
(1)同步代码块死锁
public class DeadLockTest { public static void main(String[] args) { Customer customer = new Customer(); Hotel hotel = new Hotel(); new Thread(new Dining(customer, hotel)).start(); new Thread(new Pay(customer, hotel)).start(); } } class Dining implements Runnable { private Customer customer; private Hotel hotel; public Dining(Customer customer, Hotel hotel) { this.customer = customer; this.hotel = hotel; } @Override public void run() { synchronized (customer) { customer.dining(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (hotel) { hotel.service(); } } } } class Pay implements Runnable { private Customer customer; private Hotel hotel; public Pay(Customer customer, Hotel hotel) { this.customer = customer; this.hotel = hotel; } @Override public void run() { synchronized (hotel) { hotel.bill(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (customer) { customer.pay(); } } } }
class Customer { public void pay() { System.out.println("顾客买单"); } public void dining() { System.out.println("顾客用餐"); } } class Hotel { public void service() { System.out.println("上菜"); } public void bill() { System.out.println("请先买单"); } }
(2) 同步方法死锁
public class DeadLockDemo { public static void main(String[] args) { new DeadThread(); } } class Customers { public synchronized void dining(Waiter w) { System.out.println("先吃饭再买单"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } w.doService(); } public synchronized void pay() { System.out.println("同意,先买单吧"); } } class Waiter { public synchronized void bill(Customers c) { System.out.println("先买单再吃饭"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } c.pay(); } public synchronized void doService() { System.out.println("同意,先吃饭吧"); } } class DeadThread implements Runnable { Customers customer = new Customers(); Waiter waiter = new Waiter(); public DeadThread() { new Thread(this).start(); waiter.bill(customer); } @Override public void run() { customer.dining(waiter); } }