赞
踩
死锁是多线程编程中常见的问题,当两个或多个线程互相等待对方持有的资源而无法继续执行时,就会发生死锁。这种情况下,程序会陷入无法恢复的状态,造成程序停滞或崩溃。以下是死锁产生的常见原因和解决方案。
可以举例“哲学家就餐问题”,有一群哲学家围着一张桌子吃饭,每两个哲学家之间放一个筷子,哲学家只做两件事:思考人生 或者 吃面条。 思考人生的时候就会放下筷子。吃面条就会拿起左右两边的筷子(先拿起左边, 再拿起右边),哲学家发现筷子拿不起来就会阻塞等待思考人生。五个哲学家同一时刻同时拿起左的筷子,再去拿右边的筷子就会发现筷子已被占有,就会阻塞等待,进行思考人生,哲学家们互相挂起等待就会形成“死锁”。
如何解决死锁呢,那就是打破死锁形成的四个必要条件。
其中最容易破坏的就是 “循环等待”
破坏循环等待最常用的一种死锁阻止技术就是锁排序。假设有 N 个线程尝试获取 M 把锁,就可以针对 M 把锁进行编号。N 个线程尝试获取锁的时候,都按照固定的按编号由小到大顺序来获取锁。这样就可以避免环路等待。
下面分别演示会产生环路等待的代码与不会产生环路等待的代码。
可能会产生环路等待:
public static void main(String[] args) { Object lock1 = new Object(); Object lock2 = new Object(); Thread t1 = new Thread(){ @Override public void run() { //获取锁 synchronized (lock1){ synchronized (lock2){ } } } }; Thread t2 = new Thread(){ @Override public void run() { synchronized (lock2){ synchronized (lock1){ } } } }; t1.start(); t2.start(); }
不会产生环路等待的代码:
public static void main(String[] args) { Object lock1 = new Object(); Object lock2 = new Object(); Thread t1 = new Thread(){ @Override public void run() { //获取锁 synchronized (lock1){ synchronized (lock2){ } } } }; Thread t2 = new Thread(){ @Override public void run() { synchronized (lock1){ synchronized (lock2){ } } } }; t1.start(); t2.start(); }
约定好顺序,先获取lock1锁再获取lock2锁
HashTable只是对关键方法加上了 synchronized 关键字。
这就相当于对hashtable对象直接进行加锁。
只有当两个线程访问同一个哈希桶上的数据才会进行锁冲突。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。