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



  • 相关阅读:
    $(document).Ready()方法 VS OnLoad事件 VS $(window).load()方法
    ASP.NET MVC之文件上传【二】
    ASP.NET MVC之文件上传【一】
    [JSOI2009]球队收益
    Codeforces 323 B Tournament-graph
    2017 [六省联考] T6 寿司餐厅
    [CQOI2014]数三角形
    Hdoj 3506 Monkey Party
    Loj #125. 除数函数求和(2)
    Codeforces 235 E Number Challenge
  • 原文地址:https://www.cnblogs.com/brucemengbm/p/6817889.html
Copyright © 2020-2023  润新知