zoukankan      html  css  js  c++  java
  • 什么是死锁?

    问题

    什么是死锁?请模拟写出一段 Java 死锁的核心代码?如何避免死锁?

    答案

    什么是死锁?

    有一张银行卡,小A想往里存钱,小B想取钱,存钱和取钱需要卡和密码,现在小A有卡不知道密码,小B知道密码但是没有卡,陷入无限等待状态,这就是死锁。可用jstack命令进行分析。

    死锁代码

    public class ThreadDeadlock {
    
    	public static void main(String[] args) throws InterruptedException {
    		Integer obj1 = new Integer(1);
    		Integer obj2 = new Integer(2);
    		Integer obj3 = new Integer(3);
    
    		Thread t1 = new Thread(new SyncThread(obj1, obj2), "t1");
    		Thread t2 = new Thread(new SyncThread(obj2, obj3), "t2");
    		Thread t3 = new Thread(new SyncThread(obj3, obj1), "t3");
    
    		t1.start();
    		t2.start();
    		t3.start();
    	}
    
    }
    
    class SyncThread implements Runnable {
    	private Object obj1;
    	private Object obj2;
    
    	public SyncThread(Object o1, Object o2) {
    		this.obj1 = o1;
    		this.obj2 = o2;
    	}
    
    	@Override
    	public void run() {
    		String name = Thread.currentThread().getName();
    		System.out.println(name + " acquiring lock on " + obj1);
    		synchronized (obj1) {
    			System.out.println(name + " acquired lock on " + obj1);
    			work();
    			System.out.println(name + " acquiring lock on " + obj2);
    			synchronized (obj2) {
    				System.out.println(name + " acquired lock on " + obj2);
    				work();
    			}
    			System.out.println(name + " released lock on " + obj2);
    		}
    		System.out.println(name + " released lock on " + obj1);
    		System.out.println(name + " finished execution.");
    	}
    
    	private void work() {
    		try {
    			Thread.sleep(1000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    输出结果:

    t3 acquiring lock on 3
    t3 acquired lock on 3
    t2 acquiring lock on 2
    t1 acquiring lock on 1
    t1 acquired lock on 1
    t2 acquired lock on 2    
    t2 acquiring lock on 3 # t2得到资源2的锁等待资源3的锁
    t3 acquiring lock on 1 # t3得到资源3的锁等待资源1的锁
    t1 acquiring lock on 2 # t1得到资源1的锁等待资源2的锁
    # 至此3个线程相互等待进入死锁
    

    如何避免死锁

    • 考虑加锁的顺序 每个人获取锁的顺序相同
    • 避免无限期的等待,考虑加锁的时限 每个人持有锁而未访问到资源的超时时间
    • 避免嵌套封锁
    • 只对有请求的进行封锁

    通过编程发现Java死锁

    DeadlockHandler.java

    import java.lang.management.ThreadInfo;
    
    public interface DeadlockHandler {
    	void handleDeadlock(final ThreadInfo[] deadlockedThreads);
    }
    

    DeadlockDetector.java

    import java.lang.management.ManagementFactory;
    import java.lang.management.ThreadInfo;
    import java.lang.management.ThreadMXBean;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;
    
    public class DeadlockDetector {
    
    	private final DeadlockHandler deadlockHandler;
    	private final long period;
    	private final TimeUnit unit;
    	private final ThreadMXBean mbean = ManagementFactory.getThreadMXBean();
    	private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    
    	final Runnable deadlockCheck = new Runnable() {
    		@Override
    		public void run() {
    			long[] deadlockedThreadIds = DeadlockDetector.this.mbean.findDeadlockedThreads();
    
    			if (deadlockedThreadIds != null) {
    				ThreadInfo[] threadInfos = DeadlockDetector.this.mbean.getThreadInfo(deadlockedThreadIds);
    
    				DeadlockDetector.this.deadlockHandler.handleDeadlock(threadInfos);
    			}
    		}
    	};
    
    	public DeadlockDetector(final DeadlockHandler deadlockHandler, final long period, final TimeUnit unit) {
    		this.deadlockHandler = deadlockHandler;
    		this.period = period;
    		this.unit = unit;
    	}
    
    	public void start() {
    		this.scheduler.scheduleAtFixedRate(this.deadlockCheck, this.period, this.period, this.unit);
    	}
    }
    

    DeadlockConsoleHandler.java

    public class DeadlockConsoleHandler implements DeadlockHandler {
    
    	@Override
    	public void handleDeadlock(final ThreadInfo[] deadlockedThreads) {
    		if (deadlockedThreads != null) {
    			System.err.println("Deadlock detected!");
    			Map<Thread, StackTraceElement[]> stackTraceMap = Thread.getAllStackTraces();
    			for (ThreadInfo threadInfo : deadlockedThreads) {
    				if (threadInfo != null) {
    					for (Thread thread : Thread.getAllStackTraces().keySet()) {
    						if (thread.getId() == threadInfo.getThreadId()) {
    							System.err.println(threadInfo.toString().trim());
    							for (StackTraceElement ste : thread.getStackTrace()) {
    								System.err.println("t" + ste.toString().trim());
    							}
    						}
    					}
    				}
    			}
    		}
    	}
    }
    

    使用:

    // 在启动时启动一个周期性调用线程
    DeadlockDetector deadlockDetector = new DeadlockDetector(new DeadlockConsoleHandler(), 5, TimeUnit.SECONDS);
    deadlockDetector.start();
    

    参考

  • 相关阅读:
    Dev:LookUpEdit的用法
    Excel:写入Excel单纯写入
    浅拷贝与深拷贝
    自行车的种类
    简单的话
    Excel:导入导出原文02
    VS2010中出现无法嵌入互操作类型
    U盘有时候不显示(win7 64位)
    Knockout学习之Single Page Application
    CSS点滴整理
  • 原文地址:https://www.cnblogs.com/okokabcd/p/8669286.html
Copyright © 2011-2022 走看看