点击上方“架构师小秘圈”,选择“置顶公众号”

第一时间关注架构师方面的技术干货

无意中了解到如下题目,觉得蛮好。

题目如下


public class TestSync2 implements Runnable {   int b = 100;          

   synchronized void m1() throws InterruptedException {       b = 1000;       Thread.sleep(500); //6       System.out.println("b=" + b);   }

   synchronized void m2() throws InterruptedException {       Thread.sleep(250); //5       b = 2000;   }

   public static void main(String[] args) throws InterruptedException {       TestSync2 tt = new TestSync2();       Thread t = new Thread(tt);  //1       t.start(); //2

       tt.m2(); //3       System.out.println("main thread b=" + tt.b); //4   }

   @Override   public void run() {       try {           m1();       } catch (InterruptedException e) {           e.printStackTrace();       }   }

}

该程序的输出结果?

程序输出结果


main thread b=2000b=1000或main thread b=1000b=1000

考察知识点


  • synchronize实例锁。

  • 并发下的内存可见性。

在java中,多线程的程序最难理解、调试,很多时候执行结果并不像我们想象的那样执行。所以在java多线程特别难,依稀记得大学的时候考c语言二级的时候,里面的题目是什么++和很多其他优先级的符合在一起问最后的输出结果,这类题目就想考一些运行符优先级和结合性问题。那个背背就行了,但是java多线程还是需要好好理解才行,靠背是不行的。

下面开始简单分析


该题目涉及到2个线程(主线程main、子线程)、关键词涉及到synchronized、Thread.sleep。 
synchronized关键词还是比较复杂的(可能有时候没有理解到位所以上面题目会有点误区),他的作用就是实现线程的同步(实现线程同步有很多方法,它只是一种后续文章会说其他的,需要好好研究大神Doug Lea的一些实现),它的工作就是对需要同步的代码加锁,使得每一次只有一个线程可以进入同步块(其实是一种悲观策略)从而保证线程只记得安全性。

一般关键词synchronized的用法


  • 指定加锁对象:对给定对象加锁,进入同步代码前需要活的给定对象的锁。

  • 直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。

  • 直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁。

上面的代码,synchronized用法其实就 属于第二种情况。直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。

可能存在的误区


1.由于对synchronized理解的不到为,由于很多时候,我们多线程都是操作一个synchronized的方法,当2个线程调用2个不同synchronized的方法的时候,认为是没有关系的,这种想法是存在误区的。直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。

2.如果一个调用synchronized方法。另外一个调用普通方法是没有关系的,2个是不存在等待关系的。

这些对于后面的分析很有作用。

Thread.sleep


使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁。也就是说如果有synchronized同步快,其他线程仍然不能访问共享数据。注意该方法要捕捉异常,对于后面的分析很有作用。

分析流程


java 都是从main方法执行的,上面说了有2个线程,但是这里就算修改线程优先级也没用,优先级是在2个程序都还没有执行的时候才有先后,现在这个代码一执行,主线程main已经执行了。对于属性变量 int b =100由于使用了synchronized也不会存在可见性问题(也没有必要在说使用volatile申明),当执行1步骤的时候(Thread t = new Thread(tt); //1)线程是new状态,还没有开始工作。当执行2步骤的时候(t.start(); //2)当调用start方法,这个线程才正真被启动,进入runnable状态,runnable状态表示可以执行,一切准备就绪了,但是并不表示一定在cpu上面执行,有没有真正执行取决服务cpu的调度。在这里当执行3步骤必定是先获得锁(由于start需要调用native方法,并且在用完成之后在一切准备就绪了,但是并不表示一定在cpu上面执行,有没有真正执行取决服务cpu的调度,之后才会调用run方法,执行m1方法)。这里其实2个synchronized方法里面的Thread.sheep其实要不要是无所谓的,估计是就为混淆增加难度。3步骤执行的时候其实很快子线程也准备好了,但是由于synchronized的存在,并且是作用同一对象,所以子线程就只有必须等待了。由于main方法里面执行顺序是顺序执行的,所以必须是步骤3执行完成之后才可以到4步骤,而由于3步骤执行完成,子线程就可以执行m1了。这里就存在一个多线程谁先获取到问题,如果4步骤先获取那么main thread b=2000,如果子线程m1获取到可能就b已经赋值成1000或者还没有来得及赋值4步骤就输出了可能结果就是main thread b=1000或者main thread b=2000,在这里如果把6步骤去掉那么b=执行在前和main thread b=在前就不确定了。但是由于6步骤存在,所以不管怎么都是main thread b=在前面,那么等于1000还是2000看情况,之后b=1000是一定固定的了。

多线程一些建议


  • 线程也很珍贵,所以建议使用线程池,线程池用的很多,后续准备分享下,特别重要,需要做到心中有数。

  • 给线程起名字,当线上cpu高的时候,需要用到高级jstack,如果有名称就方便很多。

  • 多线程特别需要注意线程安全问题,也需要了解jdk那些是线程安全不安全,那样使用的时候不会出现莫名其妙问题。

还有一些技巧后续文章分享在慢慢提,多线程特别重要,也特别难,希望大家也多多花心思在上面。

多线程的一些调试技巧


由于断点,所有线程经过断点的时候,都需要停下,导致这个点不停的断住,很难受,eclispe里面有条件断点,当满足条件的时候就可以停下来,那么这样就方便了。

关于线程dump分析以及后续线程内容会在后面继续分析分享。

转载声明:本文转自技术公众号匠心零度,二维码如下,欢迎关注!

推荐阅读:

技术:分布式唯一ID极简教程

职场:程序员职业规划

分享:2T架构师学习资料干货分享

觉得有帮助?请转发给更多人!


架构师小秘圈,聚集10万架构师的小圈子!不定期分享技术干货,行业秘闻!汇集各类奇妙好玩的话题和流行动向!长按左侧图片,扫码加入架构师微信群!

史上最难的一道Java面试题相关推荐

  1. 史上最难10道Java面试题!

    点击上方"朱小厮的博客",选择"设为星标" 回复"1024"获取独家整理的学习资料 这是我收集的10个最棘手的Java面试问题列表.这些问题 ...

  2. 历史上最简单的一道Java面试题,但无人能通过

    作者:方志宏 来源:zhuanlan.zhihu.com/p/57859872 这可能是历史上最简单的一道java面试题了. 题目很简单,完成代码,判断一个整数是否是奇数: public boolea ...

  3. 【微信小程序】史上最全的《Java面试题及解析》,理论+实战双管齐下!

    前言 Spring 5 于 2017 年 9 月发布了通用版本 (GA),它标志着自 2013 年 12 月以来第一个主要 Spring Framework 版本.它提供了一些人们期待已久的改进,还采 ...

  4. 【吐血整理】史上最全的《Java面试题及解析》

    前言 不知道你们发现没有,在很多互联网公司基本上都是80后,90后居多,很少还有超过40岁的程序员.可能很多人心里都有一个疑问,那就是这些40多岁的程序员都干嘛去了呢?创业显然只是极少数的人,至于管理 ...

  5. 这可能是史上功能最全的Java权限认证框架!

    点击关注公众号,Java干货及时送达 今天给大家推荐的这个开源项目超级棒,可能是史上功能最全的 Java 权限认证框架! 这个开源项目就是:sa-token . Sa-Token是什么? sa-tok ...

  6. 计算机游戏第72关,史上最难的游戏第72关 第72关通关攻略

    史上最难的游戏第72关 第72关通关攻略 2014-04-03 来源: 996手游网 编辑: 帽纸 () 史上最难的游戏是以暴走漫画为游戏剧情及背景,让无数小伙伴们抓狂的游戏.全新的关卡又更新了,为了 ...

  7. 60篇论文入选,两度夺魁,“史上最难ECCV”商汤再攀高峰

    点击上方,选择星标或置顶,不定期资源大放送! 阅读大概需要15分钟 Follow小博主,每天更新前沿干货 来源:商汤科技SenseTime 8月23-28日,全球计算机视觉三大顶会之一,两年一届的欧洲 ...

  8. 史上最难逻辑题!据说99.9%的人都做不出来……

    全世界只有3.14 % 的人关注了 爆炸吧知识 非常「逻辑」 撩人于无形 普林斯顿大学博士生 Raymond Smullyan 是一位非常厉害逻辑高手. 在Smullyan与他非常迷恋的女音乐家的第一 ...

  9. 史上最难618,公域遇冷、私域热

    作者 | 曾响铃 文 | 响铃说 过去是"流量时代",到了今天"流"将会变成"留存的留". 说这话时,戴珊(阿里国内数字商业板块总裁)正在& ...

最新文章

  1. 卸载破解的Navicat!操作所有的数据库靠它就够了!
  2. 网络文学平台如何借力智能推荐,实现阅读体验全面提升?
  3. 开源工具 @sap/ux-ui5-tooling 介绍
  4. 命令界面:使用Java中的动态API处理Redis
  5. java学习(6):数据类型
  6. JSON.parse()、eval()和JSON.stringify()
  7. hive xmlserde_hive多分隔符
  8. python分行_基于python实现对文件进行切分行
  9. php 使用支付宝SDK报错解决
  10. ios html特殊符号转化,iOS HTML特殊字符转译
  11. 信息系统项目管理案例
  12. java 四则混合运算_Java实现四则混合运算 - Sabrina amp; Joshua Java Ivory Tower - ITeye博客...
  13. 从零开始教你成为装机大神
  14. JAVA连接SQL server2000解决方法
  15. Java数据结构与算法4-树学习笔记
  16. 《重装系统》Windows纯净装机+常用工具(最简单易懂教程)--菜鸟小回
  17. Linux上安装ArcGIS for Server超详细教程——以Redhat6.5上安装ArcGIS for Server 10.3.1为例
  18. 小结Win7下开启硬盘NCQ功能
  19. MATLAB牛拉法计算潮流,matlab潮流计算
  20. GG云更新 - 测试代码

热门文章

  1. js插值计算_Python IDW插值计算及可视化绘制
  2. 安卓手机如何朗读屏幕_安卓手机的屏幕怎么投屏在电视大屏幕上
  3. 二叉排序树(完整代码)
  4. 徐直军 华为没有鸿蒙,华为徐直军:“鸿蒙”这个名字是媒体取的
  5. 2022一建改革加考英语和计算机,2021年一建考试大改革吗 考六门科目吗
  6. Linux编写一个C程序HelloWorld
  7. python——元素列表基础
  8. Fortinet网络接入及安全方案配置步骤
  9. copy的key认证
  10. 全新WiFi技术问世 更适合智能家庭和物联网