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

一、死锁

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

百科百科

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

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并发程序设计教程》

时间: 2024-10-10 01:44:10

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

《Java并发编程实战》第六章 任务运行 读书笔记

一. 在线程中运行任务 无限制创建线程的不足 .线程生命周期的开销很高 .资源消耗 .稳定性 二.Executor框架 Executor基于生产者-消费者模式,提交任务的操作相当于生产者.运行任务的线程则相当于消费者. 1. Executors 返回 ExecutorService 2. ExecutorService方法submit.execute 3. ExecutorService.submit 返回 Future 线程池,Executors方法介绍 方法名 解释 newFixedThre

《Java并发编程实战》第五章 同步容器类 读书笔记

一.同步容器类 1. 同步容器类的问题 线程容器类都是线程安全的.可是当在其上进行符合操作则须要而外加锁保护其安全性. 常见符合操作包括: . 迭代 . 跳转(依据指定顺序找到当前元素的下一个元素) . 条件运算 迭代问题能够查看之前的文章 <Java ConcurrentModificationException 异常分析与解决方式> 二.并发容器 集合类型 非线程安全 线程安全 List ArrayList CopyOnWriteArrayList Set SortedSet Concur

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

一.死锁 所谓死锁: 是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去. 百科百科 当两个以上的运算单元,双方都在等待对方停止运行,以取得系统资源,但是没有一方提前退出时,这种状况,就称为死锁.维基百科 1. 顺序死锁 最少有两个锁,一个线程获取到A锁需要获取B锁才能进行操作,而另外一个线程获取到了B锁,需要获取A锁才能执行操作,这种情况下容易出现顺序死锁. public class LeftRightDeadlock { priva

java并发编程(3)避免活跃性危险

活跃性危险 一.死锁 发生:每个人都不愿意放弃自己的锁,确想要别人的锁,这就会导致死锁  1.锁顺序死锁:如果每个线程以固定的顺序获取锁,那么至少在程序中不会出现锁顺序导致的死锁: 因为顺序固定如:所有线程:A-B-C 则无问题,如果一个A-B B-A则会发生死锁 例子1:简单死锁 public class LeftRightDeadlock { private final Object left = new Object(); private final Object right = new

《Java并发编程实战》第八章 线程池的使用 读书笔记

一.在任务与执行策略之间的隐性解耦 有些类型的任务需要明确地指定执行策略,包括: . 依赖性任务.依赖关系对执行策略造成约束,需要注意活跃性问题.要求线程池足够大,确保任务都能放入. . 使用线程封闭机制的任务.需要串行执行. . 对响应时间敏感的任务. . 使用ThreadLocal的任务. 1. 线程饥饿死锁 线程池中如果所有正在执行任务的线程都由于等待其他仍处于工作队列中的任务而阻塞,这种现象称为线程饥饿死锁. 2. 运行时间较长的任务 Java提供了限时版本与无限时版本.例如Thread

JAVA并发编程实战 读书笔记(二)对象的共享

<java并发编程实战>读书摘要 birdhack 2015年1月2日 对象的共享 JAVA并发编程实战读书笔记 我们已经知道了同步代码块和同步方法可以确保以原子的方式执行操作,但一种常见的误解是,认为关键之synchronized只能用于实现原子性或者确定临界区.同步还有另一个重要的方面:内存可见性. 1.可见性 为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制. 在没有同步的情况下,编译器.处理器以及运行时等都可能对操作的执行顺序进行一些意想不到的调整.在缺乏足够同步的多线程程

《Java并发编程实战》要点笔记及java.util.concurrent 的结构介绍

买了<java并发编程实战>这本书,看了好几遍都不是很懂,这个还是要在实战中找取其中的要点的,后面看到一篇文章笔记做的很不错分享给大家!! 原文地址:http://blog.csdn.net/cdl2008sky/article/details/26377433 Subsections  1.线程安全(Thread safety) 2.锁(lock) 3.共享对象 4.对象组合 5.基础构建模块 6.任务执行 7.取消和关闭 8.线程池的使用 9.性能与可伸缩性 10.并发程序的测试 11.显

《Java并发编程实战》读书笔记

Subsections 线程安全(Thread safety) 锁(lock) 共享对象 对象组合 基础构建模块 任务执行 取消和关闭 线程池的使用 性能与可伸缩性 并发程序的测试 显示锁 原子变量和非阻塞同步机制 一.线程安全(Thread safety) 无论何时,只要多于一个线程访问给定的状态变量.而且其中某个线程会写入该变量,此时必须使用同步来协助线程对该变量的访问. 线程安全是指多个线程在访问一个类时,如果不需要额外的同步,这个类的行为仍然是正确的. 线程安全的实例: (1).一个无状

《Java并发编程实战》第二章 线程安全性 读书笔记

一.什么是线程安全性 编写线程安全的代码 核心在于要对状态访问操作进行管理. 共享,可变的状态的访问 - 前者表示多个线程访问, 后者声明周期内发生改变. 线程安全性 核心概念是正确性.某个类的行为与其规范完全一致. 多个线程同时操作共享的变量,造成线程安全性问题. * 编写线程安全性代码的三种方法: 不在线程之间共享该状态变量 将状态变量修改为不可变的变量 在访问状态变量时使用同步 Java同步机制工具: synchronized volatile类型变量 显示锁(Explicit Lock