一起学并发编程
来源:互联网 发布:陈道明 左小青 知乎 编辑:程序博客网 时间:2024/05/01 14:05
上一章介绍过
synchronized
关键字,使用它可以给程序互斥部分加上一把锁从而达到同步的效果,但错误的用法会导致多个线程同时被阻塞….
死锁
死锁: 多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。
JAVA 中死锁产生的四个必要条件
- 互斥使用,当资源被一个线程使用(占有)时,别的线程不能使用
- 不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
- 请求和保持,当资源请求在请求其他的资源的同时保持对原有资源的占有。
- 循环等待,存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。
经典案例
先来看一段经典的死锁代码,两个方法中分别获取了class literals
方式的锁
void method1() { while (true) { synchronized (Integer.class) { System.out.println("获得 Integer.class 对象锁"); synchronized (String.class) { System.out.println("获得 String.class 对象锁"); } } }}void method2() { while (true) { synchronized (String.class) { System.out.println("获得 String.class 对象锁"); synchronized (Integer.class) { System.out.println("获得 Integer.class 对象锁"); } } }}public static void main(String[] args) { DeadLockFixed fixed = new DeadLockFixed(); new Thread(fixed::method1, "method1").start(); new Thread(fixed::method2, "method2").start();}////////////////////////日志//////////////////////////获得 Integer.class 对象锁//获得 String.class 对象锁//获得 Integer.class 对象锁//获得 String.class 对象锁//获得 Integer.class 对象锁//获得 String.class 对象锁//获得 Integer.class 对象锁//获得 String.class 对象锁//获得 Integer.class 对象锁//获得 String.class 对象锁////////////////////////日志////////////////////////
分析: method1 和 method2
都会去获取Integer
和String
两把锁,但是获取锁的顺序不一致
,在并行情况,当两个方法未及时释放自己的锁,又同时去获取另外一把锁这时候就会出现死锁情况
举个例子: 吃饭需要碗
和筷子
,小明吃饭的时候先拿筷子在拿碗,小红相反,再一次拿取餐具的时候,小明先拿到筷子,正准备拿碗的时候被小红抢先了一步拿碗,这时候都要吃饭但谁也不让谁,结果就是都饿死(死锁)
分析手段
命令: JDK本身提供了很多方便的JVM性能调优监控工具,除了集成式的VisualVM
和jConsole
外,还有jps、jstack、jmap、jhat、jstat
等小巧的命令工具,本章主要使用到jps
与jstack
做分析
jps: 过滤出Java本身的进程以及运行的引导类,就是引导main
方法所在的类。
-q 仅输出VM标识符,不包括class name,jar name,arguments in main method -m 输出main method的参数 -l 输出完全的包名,应用主类名,jar的完全路径名 -v 输出jvm参数 -V 输出通过flag文件传递到JVM中的参数(.hotspotrc文件或-XX:Flags=所指定的文件 -Joption 传递参数到vm,例如:-J-Xms48m
jstack: 主要用来查看某个Java进程内的线程堆栈信息
-l long listings,会打印出额外的锁信息,在发生死锁时可以用jstack -l pid来观察锁持有情况-m mixed mode,不仅会输出Java堆栈信息,还会输出C/C++堆栈信息(比如Native方法)
- 打开
dos
界面,输入jps
- 找到当前
main
的pid
,使用jstack pid
命令
我们可以发现method1
锁住了<0x000000076ae03e68>
等待<0x000000076ae008d8>
,method2
恰恰相反,这个时候死锁
就发生了…
日志滑动到后面,可以发现有一个Found one Java-level deadlock
,然后也告诉了我们代码在多少行,在知道问题代码所在地后,解决起来就简单了(改变锁的顺序,完美解决问题…)
补充两句
上面讲了什么是死锁以及定位问题方式,其实JDK
中,已经内置了很多锁相关的类都在java.util.concurrent.locks
包下,使用简单且可以有效的的避免死锁问题,或者使用java.util.concurrent.Semaphore(信号量)
机制,篇幅过长会导致阅读兴趣下降,所以信号量处理锁的方式在GIT
中,有兴趣可以从GIT地址获取
- 说点什么
全文代码:https://gitee.com/battcn/battcn-concurent/tree/master/Chapter1-1/battcn-thread/src/main/java/com/battcn/chapter6
- 个人QQ:1837307557
- battcn开源群(适合新手):391619659
- 一起学并发编程
- 一起学并发编程
- 一起学并发编程
- 一起学并发编程
- 一起学并发编程
- 一起学并发编程
- 一起学并发编程
- 一起学并发编程
- 一起学并发编程
- 一起学并发编程
- 一起学并发编程
- 一起学编程(1)
- 看动画学并发编程
- 看动画学并发编程
- 面向方面编程,有兴趣的一起学
- 《与孩子一起学编程》译者序
- 《与孩子一起学编程》书评
- 与孩子一起学编程1
- 欧几里德算法 -- 求最大公约数
- Runtime Permissions(郭霖CSDN公开课)
- HLS-序
- lua pcall error
- SVN服务器搭建和使用(一)
- 一起学并发编程
- Request的getParameter和getAttribute方法的区别
- 优达学城《计算机科学导论》小结
- 【实用】SAP修改记录表开发
- 《20171113》
- Linux安装图形化桌面
- 如何将arm-linux-gcc编译的动态链接helloworld在Android上运行
- ceph KRBD 内核RBD模块 rbd 快照 克隆 删除 恢复
- ssd textboxes Check failed: channels == img_channels (3 vs. 1)