文档章节

为什么面试必问线程状态?你的回答满分了吗

Z_J_H
 Z_J_H
发布于 2019/12/13 21:21
字数 1107
阅读 19
收藏 0

看很多同学的面经、网上的面试资料,都不约而同的提到了一个基础问题:“你知道线程有几种状态吗?状态之间的扭转是怎样的?”,有准备的同学都知道有五种:New(新建)、Runnable(可运行)、Blocked(被阻塞)、Waiting(等待)、Timed waiting(计时等待)、Terminated(被终止), 通过new、wait、notify、sychroniezd、lock等操作进行状态扭转。

但,这是面试官的期待的答案吗? 面试官考察的仅仅是你的Java基础吗? 在实际工作中,线程状态有用吗?


下面通过一个线上排查case来回答这个问题。

有一个线上离线数据服务,每天早上定时发送日报给产品。有一天产品反馈说数据没了,到公司赶紧排查,查看日志、监控发现任务确实没有执行,日志里也没发现任何Error或者Exception,怀疑可能是代码某个位置卡住了,通过 jstack 查看线程堆栈,发现“GET-DATA”全部处于WAITING状态

"GET-DATA-14" #14 prio=5 os_prio=31 tid=0x00007fa317a94800 nid=0x5503 waiting on condition [0x0000700003f68000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x000000076b546838> (a java.util.concurrent.FutureTask)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
	at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:429)
	at java.util.concurrent.FutureTask.get(FutureTask.java:191)
	at jstack.JstackTest$1.call(JstackTest.java:30)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

"GET-DATA-13" #13 prio=5 os_prio=31 tid=0x00007fa31811d800 nid=0x3e03 waiting on condition [0x0000700003e65000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x000000076b68e258> (a java.util.concurrent.FutureTask)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
	at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:429)
	at java.util.concurrent.FutureTask.get(FutureTask.java:191)
	at jstack.JstackTest$1.call(JstackTest.java:30)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

一行日志引起了注意

"GET-DATA-13" #13 prio=5 os_prio=31 tid=0x00007fa31811d800 nid=0x3e03 waiting on condition [0x0000700003e65000]
    java.lang.Thread.State: WAITING (parking)
   ...
    at java.util.concurrent.FutureTask.get(FutureTask.java:191)
    at jstack.JstackTest$1.call(JstackTest.java:30)

很明显“GET-DATA”阻塞在了FutureTask的get方法,对照业务代码JstackTest.java:30, 发现对应位置是将一个异步逻辑放到线程池中执行,并等待结果。 进一步排查代码发现,JstackTest 本身提交来一个异步任务,并且异步任务内部又提交了一个任务,并且使用的同一个线程池,简化后的demo代码如下:

public class JstackTest {
    private ExecutorService executorService = Executors.newFixedThreadPool(1);

    public void test() throws ExecutionException, InterruptedException {
        Future<Object> outerFuture = executorService.submit(() -> {
            Future<Object> innerFuture = executorService.submit(() -> {
                // do something
                return null;
            });

            innerFuture.get();
            return null;
        });

        outerFuture.get();
    }
}

从上面的demo可以看到,outerFuture会等待innerFuture的处理结果,当线程池的工作线程都在处理outerFuture的时候,innerFuture只能被扔到LinkedBlockingQueue中等待执行。从而形成了死锁。

找到问题,解决就很简单了。

  1. 设置Future.get的超时时间
  2. outerFuture和innerFuture做线程池隔离,使用各自独立的线程池

回到最开始的问题,怎么回答“你知道线程有几种状态吗?状态之间的扭转是怎样的?”呢?

线程有五种状,分别是***** , 通过new、wait、notify、sychroniezd、lock等操作进行状态扭转,一般线上问题排查中经常会遇到线程处于Waiting/Blocked状态,比如有一次怎么怎么的

立马就体现出你的线上故障排查能力

这是我在网上找的一个岗位要求(第6条)

1、统招本科及以上学历,三年以上的Java开发经验;
2、熟练掌握OO思想,具备扎实的抽象编程、设计能力及良好的单元测试习惯;
3、熟练掌握MySQL、Mongo、Redis的开发使用并了解各结构的性能;
4、熟悉Linux平台常用操作命令及具有编写脚本的能力;
5、熟悉Spring、Mybatis、Zookeeper、dubbo等常用开源项目;
6、熟练掌握多线程编程、JVM内存管理、类加载机制等;熟练掌握Java系统的故障排查和性能调优技能;
7、具有高日千万级以上PV电商业务架构、社交平台开发者优先录用;
8、具备较强的学习能力和责任心,良好的沟通能力、文档编写能力、有github开源项目者优先。


觉得还不错的话,留个👍让我看到你!!

© 著作权归作者所有

Z_J_H
粉丝 1
博文 1
码字总数 1107
作品 0
广元
私信 提问
一名3年工作经验的java程序员应该具备的职业技能

一名3年工作经验的Java程序员应该具备的技能,这可能是Java程序员们比较关心的内容。我这里要说明一下,以下列举的内容不是都要会的东西—-但是如果你掌握得越多,最终能得到的评价、拿到的薪...

老道士
2018/07/16
210
2
mysql主从复制面试宝典!面试官都没你懂得多!(11)

     有些同学连集群和主从都分不清楚的,这里我说一下他们最本质的区别,其实也就是data-sharing和nothing-sharing的区别。集群是共享存储的。主从复制中没有任何共享。每台机器都是独立...

java进阶架构师
2017/11/11
0
0
记一次阿里巴巴一面经历,作为一名java程序员终于找到了自己差距!

面试前的故事 上周在拉勾上收到一个蚂蚁金服的大哥要我的简历,当时很惊讶,居然有蚂蚁金服的找到我,然后想都没想就给了。 受宠若惊呀,我知道自己的水平跟阿里的差距有多远,以前一直没用勇...

我最喜欢三大框架
2019/05/13
41
0
「mysql优化专题」主从复制面试宝典!面试官都没你懂得多!(11)

内容较多,可先收藏,目录如下: 一、什么是主从复制 二、主从复制的作用(重点) 三、主从复制的原理(重点) 四、三步轻松构建主从 五、必问面试题干货分析(重点) 一、什么是主从复制: ...

java进阶架构师
2018/01/02
0
0
mysql优化之主从复制面试宝典!面试官都没你懂得多!

     有些同学连集群和主从都分不清楚的,这里我说一下他们最本质的区别,其实也就是data-sharing和nothing-sharing的区别。集群是共享存储的。主从复制中没有任何共享。每台机器都是独立...

java进阶架构师
2017/11/07
0
0

没有更多内容

加载失败,请刷新页面

加载更多

用Markdown编程之类型

类型就是约定。而现有的类型是单纬度的。用标注法编程好处就是可以多维度。 类型基础分为: 虚 实 在此之上分为: 根 寄存器级 联 内存级 外 网络级 虚:说白了就是指针或索引之类的概念。之...

dwcz
18分钟前
56
0
WPF中的StaticResource和DynamicResource有什么区别?

在WPF中使用画笔,模板和样式等资源时,可以将它们指定为StaticResources <Rectangle Fill="{StaticResource MyBrush}" /> 或者作为DynamicResource <ItemsControl ItemTemplate="{DynamicR......

javail
44分钟前
49
0
Day07继承中的面试题 答案

1. 每一个构造方法的第一条语句默认都是:super() Object类最顶层的父类。 class Zi extends Fu{ public int num = 20; public Zi(){ //super(); System.out.println("zi"); } 2.class Test......

Lao鹰
49分钟前
46
0
每天AC系列(四):四数之和

1 题目 Leetcode第18题,给定一个数组与一个target,找出数组中的四个数之和为target的不重复的所有四个数. 2 暴力 List<List<Integer>> result = new ArrayList<>();if (nums.length == 4 &......

Blueeeeeee
59分钟前
70
0
git clone --mirror和git clone --bare有什么区别

git clone帮助页面上有关于--mirror : 设置远程存储库的镜像。 这意味着--bare 。 但没有详细介绍--mirror克隆与--bare克隆--mirror不同。 #1楼 克隆将从远程服务器复制参考,并将其填充到名...

技术盛宴
今天
86
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部