《Java并发编程实战》第十章 避免活跃性危急 读书笔记

2023-06-14,,

版权声明:本文为博主原创文章,未经博主同意不得转载。 https://blog.csdn.net/love_world_/article/details/27635333

一、死锁

所谓死锁: 是指两个或两个以上的进程在运行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用。它们都将无法推进下去。

百科百科

当两个以上的运算单元,两方都在等待对方停止运行,以取得系统资源。可是没有一方提前退出时,这样的状况,就称为死锁。维基百科

1. 顺序死锁
最少有两个锁,一个线程获取到A锁须要获取B锁才干进行操作。而另外一个线程获取到了B锁。须要获取A锁才干运行操作。这样的情况下easy出现顺序死锁。

public class LeftRightDeadlock {

	private final Object left = new Object();
private final Object right = new Object(); public void leftRight() {
synchronized (left) {
synchronized (right) {
// doSomething();
}
}
} public void rightLeft() {
synchronized (right) {
synchronized (left) {
// doSomething();
}
}
}
}

2. 动态的锁顺序死锁

	public void transferMoney(Account fromAccount, Account toAccount, DollarAmount anount)
throws InsufficientResourcesException {
synchronized (fromAccount) {
synchronized (toAccount) {
if (fromAccount.getBalance().compareTo(amount) < 0) {
throw new InsufficientResourcesException();
} else {
fromAccount.debit(anount);
toAccount.credit(anount);
}
}
}
}

A: transferMoney(myAccount, yourAccount, 10);
B: transferMoney(yourAccount, myAccount, 20);

由外部传入的变量全部锁的条件。可是由以上传入的变量能够看到,这样的情况下会出现一个线程先获取myAccount锁在申请yourAccount锁,而另外一个线程相反先获取yourAccount锁在申请myAccount锁。

	private static final Object tieLock = new Object();

	public void transferMoney(final Account fromAccount, final Account toAccount, final DollarAmount anount)
throws InsufficientResourcesException {
class Helper{
public void transfer() throws InsufficientResourcesException {
if (fromAccount.getBalance().compareTo(amount) < 0){
throw new InsufficientResourcesException();
} else{
fromAccount.debit(anount);
toAccount.credit(anount);
}
}
} int fromHash = System.identityHashCode(fromAccount);
int toHash = System.identityHashCode(toAccount); if (fromHash < toHash){
synchronized (fromAccount){
synchronized (toAccount) {
new Helper().transfer();
}
}
} else if (fromHash > toHash){
synchronized (toAccount){
synchronized (fromAccount) {
new Helper().transfer();
}
}
} else {
synchronized (tieLock) {
synchronized (fromAccount) {
synchronized (toAccount) {
new Helper().transfer();
}
}
}
}
}

3. 在协作对象之间发生的死锁

class Taxi {

	private Point location, destination;
private final Dispatcher dispatcher; public Taxi(Dispatcher dispatcher) {
this.dispatcher = dispatcher;
} public synchronized Point getLocation(){
return location;
} public synchronized void setLocation(Point location){
this.location = location;
if (location.equals(destination)){
dispatcher.notifyAvaliable(this);
}
} } class Dispatcher { private final Set<Taxi> taxis;
private final Set<Taxi> avaliableTaxis; public Dispatcher(){
taxis = new HashSet<Taxi>();
avaliableTaxis = new HashSet<Taxi>();
} public synchronized void notifyAvaliable(Taxi taxi) {
avaliableTaxis.add(taxi);
} public synchronized Image getImage(){
Image image = new Image();
for (Taxi t :taxis){
image.drawMarker(t.getLocation());
}
return image;
} }

4. 开放调用
 -- 待填充

5. 资源死锁
外部锁常被忽视而导致死锁,比如数据库的锁

二、死锁的避免与诊断

1. 支持定时的死锁
存在一些预防死锁的手段。比方Lock的tryLock,JDK 7中引入的Phaser等。

2. 通过线程转储信息来分析死锁
通过Dump线程的StackTrace,比如linux下运行命令 kill -3 <pid>,或者jstack –l <pid>,或者使用Jconsole连接上去查看线程的StackTrace,由此来诊断死锁问题。

三、其它活跃性危急

1. 饥饿
2. 糟糕的响应性
3. 活锁

四、锁的使用

使用支持CAS的数据结构。避免使用锁,如:AtomicXXX、ConcurrentMap、CopyOnWriteList、ConcurrentLinkedQueue
死锁常常是无法全然避免的。鸵鸟策略被非常多基础框架所採用。

存在检測死锁的办法

五、參考资料:

《温绍锦 - Java并发程序设计教程》

《Java并发编程实战》第十章 避免活跃性危急 读书笔记的相关教程结束。

《《Java并发编程实战》第十章 避免活跃性危急 读书笔记.doc》

下载本文的Word格式文档,以方便收藏与打印。