这是最新的大厂面试系列,还原实际场景,提取知识点分享给大家。
昨天,有一个同伴给蚂蚁面试实习生工作。 面试官问了他过去常说的问题。 你说Java做线程有什么方法?
这个yjddmn心里窃喜,这个老生常谈的问题我早就背熟了,说得很流利。
在Java中创建线程有两种方法。
继承Thread类并重写run (方法
实现Runnable接口,覆盖接口中的run ()方法,并将Runnable接口的实现提交给Thread
面试官:(拿出白纸)那就写一下这两种方式吧!
哥哥:)这有什么难的! 是的~
publicstaticvoidmain (字符串[ ] args ) {
//第一个
MyThread myThread=new MyThread (;
myThread.start (;
//第二个
new Thread ()- System.out.println ) '自身实现的run-2 ' ) ).start );
}
publicstaticclassmythreadextendsthread {
@Override
公共void run (}
System.out.println (自己实现的run-1 );
}
}
面试官:嗯,那除了这两个以外,还有其他制作线程的方法吗?
因为这些简单的问题很难打败yjddmn,所以我考虑了Java5以后的Executors。 Executors工具类可用于创建线程池。
哥哥: Executors工具类用于创建线程池。 此线程池可以指定线程数,也可以不指定线程数。 也可以指定计时器的线程池。 常用方法如下:
newfixedthreadpool(intnthreads ) :创建固定数量的线程池
newCachedThreadPool (:创建缓存线程池
newSingleThreadExecutor (:创建单个线程
newscheduledthreadpool (intcorepoolsize ) :创建计时器线程池
面试官:嗯,OK,我们还是对你写的代码,再问一次。
此时,yjddmn有一种不祥的预感。 自己代码的写法是不是有点问题? 还是问我实现下层?
面试官:你写的两个线程的创建方法与run (方法有关。 你知道Thread的run )方法具体是怎么实现的吗?
果然问了源代码,这个yjddmn之前看了一点,所以没怎么慌张。 想起来了,对面试官说。
哥哥: emm……Thread的run ) )因为方法很少,所以对一个if进行判断。
@Override
公共void run (}
if (目标!=空) {
target.run (;
}
}
一个target对象确定该变量是否为空。 如果不为空,则执行target对象中的run ()方法。 否则,我什么都不做。 这个target对象是我们所说的Runnable :
/* What will be run. */
私有运行目标;
面试官:嗯,那你知道这个Runnable类吗?
哥哥:我知道了。 这个Runnable类很简单。 是抽象的方法。
@ functional接口
公共接口运行nable {
公共abstract void run (;
}
这个抽象方法也是run ()! 如果使用Runnable接口,则必须实现此run ()方法。 此Runnable类具有@FunctionalInterface注释,因此可以使用函数式编程。
哥哥继续这样说。 因为“突然变得有自信了”,所以这对应于刚才提到的创建线程的两种方法。 如果我使用第一种方法,继承Thread类,然后重写run ) )方法,则上面的默认run ) )方法不执行,也就是说,不确定target,而是重写的run )方法的
如果我在使用第二种方法,则以实现Runnable接口的方式运行默认的run (运行方法,确定target不为空,然后在Runnable接口上实现的run ) )方法
面试官: OK,可以。 我再问你问题。
哥哥:(暗自高兴) )
面试官:那么,如果我继承了Thread类,同时实现了Runnable接口,比如说,最后打印什么信息?
面试官一边说,一边拿起刚才这个哥哥写的代码,简单地修改了一下:
public static void main(String[] args) {
new Thread(() -> System.out.println("runnable run")) {
@Override
public void run() {
System.out.println("Thread run");
}
}.start();
}
这小哥,突然有点懵,好像从来没想过这个问题,一时没有什么思路,于是回答了个:会打印 “Thread run” 吧……
面试官:答案是对的,但是为什么呢?
这小哥一时没想到原因,于是面试官让他回去可以思考思考,就继续下一个问题了。
亲爱的读者朋友,你们知道为什么吗?你们可以先思考一下。
其实这个答案很简单,我们来分析一下代码便知:其实是 new 了一个对象(子对象)继承了Thread对象(父对象),在子对象里重写了父类的run()方法;然后父对象里面扔了个Runnable进去,父对象中的run()方法就是最初那个带有 if 判断的run()方法。
好了,现在执行start()后,肯定先在子类中找run()方法,找到了,父类的run()方法自然就被干掉了,所以会打印出:Thread run。
如果我们现在假设子类中没有重写run()方法,那么必然要去父类找run()方法,父类的run()方法中就得判断是否有Runnable传进来,现在有一个,所以执行Runnable中的run()方法,那么就会打印:Runnable run 出来。
说白了,就是问了个 Java 语言本身的父子继承关系,会优先执行子类重写的方法而已,只是借这个场景,换了个提问的方式,面试者可能一时没反应过来,有点懵也是正常的,如果直接问,傻子都能回答的出来。
后记:通过这道简单的面试题,帮大家分析了一下在创建线程过程中的源码,可以看出来,面试过程中,面试官更加看重一些原理性的东西,而不是背一下方式就行了。同时也能看的出,面试大厂,需要做好充分的准备。另外,在面试的时候要冷静,可能有些问题并没有太难,回答不出来只是当时太紧张造成的。
这篇文章就写到这,最后祝大家都能面试成功。
如果觉得有帮助,希望大家关注小编并帮小编转发,希望大家都可以找到自己心仪的大厂,顺利拿下offer。
原文链接:https://blog.csdn.net/eson_15/article/details/105393279?depth_1-utm_source=distribute.pc_category.none-task-blog-hot-2&request_id=&utm_source=distribute.pc_category.none-task-blog-hot-2