文章插图
执行sleep的时候会让出CPU,但不是释放锁 。
package cn.itcast.thread;/** 学习死锁的概念和解决死锁 */public class DeadLock { // 定义两个对象作为锁 private static Object objA = new Object(); private static Object objB = new Object(); public static void main(String[] args) { // 线程1 Thread t1 = new Thread(() -> { // 同步锁 synchronized (objA){ try { // 线程休眠(让出CPU,不释放锁) Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("AAAAAAA"); // 同步锁 synchronized (objB){ System.out.println("BBBBBBB"); } } }); // 线程2 Thread t2 = new Thread(() -> { // 同步锁 synchronized (objB){ System.out.println("CCCCCCC"); // 同步锁 synchronized (objA){ System.out.println("DDDDDDD"); } } }); t1.start(); t2.start(); }}
上面的代码只是演示死锁的场景,在现实中你可能不会写出这样的代码 。但是,在一些更为复杂的场景中,你可能会遇到这样的问题,比如t1拿到锁之后,因为一些异常情况没有释放锁(死循环) 。又或者是t1拿到一个数据库锁,释放锁的时候抛出了异常,没释放掉 。一旦出现死锁,业务是可感知的,因为不能继续提供服务了 。查看线程执行情况
打开cmd命令dos窗口输入如下命令
jps命令:查看Java程序进程id信息
jstack命令:查看指定进程堆栈信息
文章插图
文章插图
如何避免死锁?
现在,我们介绍避免死锁的几个常见方法:
- 避免一个线程同时获取多个锁 。
- 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源 。
- 尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制 。
1.什么是死锁: 多线程竞争共享资源,导致线程相互等待,程序无法向下执行 。
2.死锁产生的条件
- 有多个线程
- 有多把锁
- 有同步代码块嵌套
文章插图
测试代码
代码演示串行和并发执行并累加操作的时间,请分析: 下面的代码并发执行一定比串行执行快吗?
package cn.itcast.thread;public class Test4 {// 定义变量private static final long count = 1000000000;public static void main(String[] args) throws InterruptedException {concurrency();serial();}// 定义方法1(使用线程)private static void concurrency() throws InterruptedException {long start = System.currentTimeMillis();// 创建线程 循环累加Thread thread = new Thread(() -> {int a = 0;for (long i = 0; i < count; i++) {a += 5;}});// 开启线程thread.start();// 循环累减int b = 0;for (long i = 0; i < count; i++) {b--;}long time = System.currentTimeMillis() - start;// thread.join();System.out.println("concurrency :" + time + "ms,b=" + b);}// 定义方法2 (不用线程)private static void serial() {long start = System.currentTimeMillis();// 循环累加int a = 0;for (long i = 0; i < count; i++) {a += 5;}// 循环累减int b = 0;for (long i = 0; i < count; i++) {b--;}long time = System.currentTimeMillis() - start;System.out.println("serial:" + time + "ms,b=" + b );}}
测试结果上述问题的答案是“不一定”,测试结果如表所示:
文章插图
当并发执行累加操作不超过百万次时,速度会比串行执行累加操作要慢 。那么,为什么并发执行的速度会比串行慢呢?这是因为线程有创建和上下文切换的开销 。
上下文切换
- 即使是单核处理器也支持多线程执行代码 , CPU 通过给每个线程分配CPU 时间片来实现这个机制 。时间片是CPU 分配给各个线程的时间,因为时间片非常短,所以CPU 通过不停地切换线程执行,让我们感觉多个线程是同时执行的,时间片一般是几十毫秒(ms) 。
- CPU 通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务 。但是,在切换前会保存上一个任务的状态,以便下次切换回这个任务时 , 可以再加载这个任务的状态 。所以任务从保存到再加载的过程就是一次上下文切换 。
推荐阅读
- “正科级”公务员退休后有多少钱?40年工龄的话,预计是这个数
- 女人对你有好感,哪怕嘴上不说,这7个肢体语言也藏不住
- “无性婚姻”有多可怕?听听3个过来人的故事,希望你能引以为戒
- 家里放了几年的红茶、绿茶、普洱茶,还能喝吗?医生告诉你实话
- 求求你们别再换脸了,就像好好的一盘菜吃出苍蝇的感觉!
- 拒认儿子巴图20年,晚年态度翻转,是居心叵测,还是真后悔?
- 教你自己制作花生酱,教你自制花生酱
- 微博该咋得才可以删除评论,为什么微博评论删除后还有显示
- 《我知道我爱你》热播:和冬天适配的偶像剧
- 李善均离世早有端倪?留下遗书后离家,现场有点燃闪电弹的痕迹