概念解析-死锁&饥饿&活锁

1.死锁:通俗地说,死锁是两个或者多个线程,相互占用对方需要的资源,而都不进行释放,导致彼此之间都相互等待对方释放资源,产生了无限制等待的现象,死锁一旦发生,如果没有外力介入,这种等待将永远存在,从而对程序产生严重的影响

用来描述死锁的一个有名的场景是“哲学家就餐”问题,用一个简单的例子来模拟下,有两个科学家和两把叉子

package LockTest;

public class DeadLock extends Thread{
	protected Object tool;
	static Object fork1=new Object();
    static Object fork2=new Object();
    public DeadLock(Object obj){
    	this.tool=obj;
    	if(tool==fork1){
    		this.setName("哲学家A");
    	}
    	else if(tool==fork2){
    		this.setName("哲学家B");
    	}
    }
    
    public void run(){
    	if(tool==fork1){
    		synchronized(fork1){
    			try{
    				Thread.sleep(500);
    			}catch(Exception e){
    				e.printStackTrace();
    			}
    			synchronized(fork2){
    				System.out.println("哲学家A开始吃饭了");
    			}
    		}
    	}
    	if(tool==fork2){
    		synchronized(fork2){
    			try{
    				Thread.sleep(500);
    			}catch(Exception e){
    				e.printStackTrace();
    			}
    			synchronized(fork1){
    				System.out.println("哲学家B开始吃饭了");
    			}
    		}
    	}

    }
    
	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		DeadLock PhilosopherA=new DeadLock(fork1);
		DeadLock PhilosopherB=new DeadLock(fork2);
		PhilosopherA.start();
		PhilosopherB.start();
		Thread.sleep(1000);
	}

}

哲学家A先占用叉子1,哲学家B占用叉子2,接着他们就相互等待,都没有办法同时获得两个叉子用餐。实际环境中,遇到了这种情况,通常的表现就是相关的进程不再工作,并且CPU占用率为0(因为死锁的线程不占用CPU),可以使用JDK确认问题:使用jps命令得到java进程的进程ID,接着使用jstack命令得到线程的线程堆栈:


找到了死锁的存在,并在最后可以看出两者互相等待的锁的ID


2.饥饿

某一个或者多个线程因为种种原因无法获得所需要的资源,导致一直无法执行,比如它的线程优先级可能太低,而高优先级的线程不断抢占它需要的资源,导致低优先级线程无法工作。与死锁相比,饥饿还是有可能在未来一段时间内解决的,比如高优先级的线程已经完成任务,不再疯狂地执行

3.活锁

任务或者执行者没有被阻塞,由于某些条件没有满足,导致一直重复尝试、失败、尝试、失败。活锁和死锁的区别在于,处于活锁的实体时在不断改变状态,活锁有可能自行解开而死锁不能

猜你喜欢

转载自blog.csdn.net/Autumn03/article/details/80928942