前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java并发-死锁

Java并发-死锁

作者头像
Fisherman渔夫
发布2020-02-18 16:29:02
7590
发布2020-02-18 16:29:02
举报
文章被收录于专栏:渔夫渔夫

一、死锁的简单概念

 所谓死锁是指两个或两个以上的线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无其余方法作用,它们都将无法推进下去。  网友们有一个生动形象的比方:两个人面对面过独木桥,甲和乙都已经在桥上走了一段距离,即占用了桥的资源,甲如果想通过独木桥的话,乙必须退出桥面让出桥的资源,让甲通过,但是乙不服,为什么让我先退出去,我还想先过去呢,于是就僵持不下,导致谁也过不了桥,这就是死锁。其实死锁形成的关键就是:谁也不让谁,谁都不会主动地让步。


二、死锁的简单例子

例子1:

代码语言:javascript
复制
//类1,d1方法为需要获得类1以及类2对象的方法
class DeadLock {
	private OtherService otherService;

	private static final Object LOCK = new Object();

	public DeadLock(OtherService otherService){
		this.otherService = otherService;
	}

	public void d1(){
		synchronized (LOCK){
			System.out.println("d1===========");
			otherService.o2();
		}
	}

	public void d2(){
		synchronized (LOCK){
			System.out.println("d2===========");
		}
	}

}

//类1,o1方法为需要获得类1以及类2对象的方法
class OtherService {
	private DeadLock deadLock;

	private static final Object LOCK = new Object();

	public void o1() {
		synchronized (LOCK){
			System.out.println("o1===========");
			deadLock.d2();
		}
	}

	public void o2() {
		synchronized (LOCK){
			System.out.println("o2===========");
		}
	}

	public void setDeadLock(DeadLock deadLock) {
		this.deadLock = deadLock;
	}
}


public class DeadLockTest {
	public static void main(String[] args) {
		OtherService otherService = new OtherService();
		DeadLock deadLock = new DeadLock(otherService);
		otherService.setDeadLock(deadLock);

		/**
		 * cmd通过jps命令查看该main线程的端口号
		 * 再通过jstack + 上面查到的端口号的命令查看栈情况
		 * 可以分析出来死锁情况:是否存在死锁
		 */
		new Thread(()->{
			while (true){
				deadLock.d1();
			}
		}).start();
		new Thread(()->{
			while (true){
				otherService.o1();
			}
		}).start();

	}

}

 上述代码描述了Java中死锁最简单的情况,一个线程Thread-0持有锁L0并且申请获得锁L1,而另一个线程Thread-1持有锁L1并且申请获得锁L0,因为默认的锁申请操作都是阻塞的,所以线程Thrad-0和Thread-1永远被阻塞了。导致了死锁。  虽然这种僵持情况由于线程程序运行时间可能错开,而不在程序运行的开始马上发生,但是这种结构的程序,若无其他代码进行死锁去除保障,那么死锁现象一定会发生。

例子2:

代码语言:javascript
复制
public class DeadLock_join {
    public static void main(String[] args) {
        System.out.println("main线程开始运行");

        try {
            Thread.currentThread().join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("如果打印出这段话则证明没有死锁");
    }
}

我们可以查看控制台观察到语句:如果打印出这段话则证明没有死锁永远得不到执行。这也是死锁的一个典型例子: 使用自己的线程对象作为同步锁,调用join方法,那么会造成死锁。


三、死锁的CMD查阅操作演示:

  1. cmd通过jps命令查看该main线程的端口号 Win+R,输入cmd,即可保证打开CMD端口。输入jps,根据main方法所在类的名字,找到线程的端口号。
在这里插入图片描述
在这里插入图片描述
  1. 再通过jstack + 上面查到的端口号的命令查看栈情况
在这里插入图片描述
在这里插入图片描述

1)可以看到线程Thread-0以及Thread-1线程发生了阻塞情况,即图中最后一行的Found 1 deadlock提示所示。 2) -locked则表示线程目前锁占据的锁ID,而waiting to lock后加ID代表被当前线程锁等待的,其他线程占据的未释的锁。

 我们发现线程Thread-0锁占据的锁,正是Thread-1锁等待的,而Thread-0等待的锁恰好是Thread-1锁占据的锁,除非线程等待的锁被其他线程释放了,那么当前线程才会释放自己的锁,那么其他线程才有机会获得当前线程的锁。恰恰因为线程的不主动让步,形成了死锁,2个线程”卡住了“。

注意事项: 很多人可能在CMD上输入jps/jstack等命令却不被系统识别,一般都是JDK环境在Win系统安装不正确导致,建议重新j检查环境变量是否安装正确。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、死锁的简单概念
  • 二、死锁的简单例子
  • 三、死锁的CMD查阅操作演示:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档