Java面试挂在线程创建后续,不要再被八股文误导了!创建线程的方式只有1种

简介: Java面试挂在线程创建后续,不要再被八股文误导了!创建线程的方式只有1种

写在开头

在上篇博文中我们提到小伙伴去面试,面试官让说出8种线程创建的方式,而他只说出了4种,导致面试挂掉,在博文中也给出了10种线程创建的方式,但在文章的结尾我们提出:真正创建线程的方式只有1种,剩下的衍生品多是套壳,那么在这篇文章中,我们来解释一下缘由!

线程创建之源

OK!咱们闲话少叙,直接进入正题,回顾一下通过实现Runnable接口,重写run方法创建线程的方式,真的可以创建一个线程吗?来看下面这段demo。

【代码示例1】
public class Test  implements Runnable{
   

    public static void main(String[] args) {
   
        Test test = new Test();
        test.run();
    }
    @Override
    public void run() {
   
           System.out.println(Thread.currentThread().getName()+":"+"runnable线程");
    }
}
输出:
main:runnable线程

虽然这里我们实现了Runnable接口并重写了run方法,但执行结果中输出的线程却是主线程,这可我们调用普通的方法一样,仍旧依靠的主线程驱动,那怎么样创建一个线程呢?

【代码示例2】
public class Test  implements Runnable{
   

    public static void main(String[] args) {
   
        Test test = new Test();
        new Thread(test).start();
    }
    @Override
    public void run() {
   
        System.out.println(Thread.currentThread().getName()+":"+"runnable线程");
    }
}
输出:
Thread-0:runnable线程

这个demo中,我们在外面套了一层Thread,然后调用start方法,最终输出的结果就是一个全新的Thread-0线程,从而实现了线程的创建。

得出结论

我们继续换Callable、FutureTask、ThreadGroup、匿名内部类或Lambda表达式等类或接口,发现均无法直接创建一个线程,必须借助Thread的start();

而例如ExecutorService线程池、ForkJoin线程池、CompletableFuture类、Timer定时器类、parallelStream并行流等等,如果有去看过它们源码的小伙伴应该清楚,它们最终都依赖于Thread.start()方法创建线程。

因此,我们在这里可以大胆的得出这样的一个结论:

在Java中创建线程的方式只有一种:通过Thread.start()调用 start()方法,会启动一个线程并使线程进入就绪状态,当分配到时间片后开始运行。 start() 会执行线程的相应准备工作,然后自动执行 run() 方法的内容

线程体与线程的区别

文章写到这里,我们一起再来思考一个问题,既然Runnable和Callable接口和Thread类一样需要重写他们提供的run()/call()方法,又没有创建线程,那它们究竟做了什么呢?
这个直接给出答案:他们经过重写,确定了线程体,那线程体与线程又有何区别?我们来看看文心一言怎么说。
image.png

总结一句话:线程体是线程的核心部分,负责执行线程的具体任务。

所以说无论是Thread中的run还是Runnable中的run,Callable中的call方法,内部所实现的都是线程需要执行的具体内容也就是线程体

总结

基于以上的分析,若我们在面试中再次遇到:“Java线程有几种创建方式?”的考题,就可以这样回答啦:

Java中创建线程的方式有很多种,在《Java技术卷》和《Java编程思想》中提供了实现Runnable、Callable接口、继承Thread类、创建线程池这四种常见方式,我们还可以通过ForkJoin线程池、CompletableFuture类、Timer定时器类、parallelStream并行流、匿名内部类或Lambda表达式等多种方式去实现,但这些都不是真正意义上的创建线程,严格意义上,Java创建线程的方式只有一种那就是通过new Thread().start()创建,Runnable、Callable接口只是重写了线程的线程体,用来确定我们线程需要执行的内容。

结尾彩蛋

如果本篇博客对您有一定的帮助,大家记得留言+点赞+收藏呀。原创不易,转载请联系Build哥!

目录
相关文章
|
2天前
|
Java API
详细探究Java多线程的线程状态变化
Java多线程的线程状态主要有六种:新建(NEW)、可运行(RUNNABLE)、阻塞(BLOCKED)、等待(WAITING)、超时等待(TIMED_WAITING)和终止(TERMINATED)。线程创建后处于NEW状态,调用start()后进入RUNNABLE状态,表示准备好运行。当线程获得CPU资源,开始执行run()方法时,它处于运行状态。线程可以因等待锁或调用sleep()等方法进入BLOCKED或等待状态。线程完成任务或发生异常后,会进入TERMINATED状态。
|
2天前
|
存储 安全 Java
Java多线程中线程安全问题
Java多线程中的线程安全问题主要涉及多线程环境下对共享资源的访问可能导致的数据损坏或不一致。线程安全的核心在于确保在多线程调度顺序不确定的情况下,代码的执行结果始终正确。常见原因包括线程调度随机性、共享数据修改以及原子性问题。解决线程安全问题通常需要采用同步机制,如使用synchronized关键字或Lock接口,以确保同一时间只有一个线程能够访问特定资源,从而保持数据的一致性和正确性。
|
2天前
|
监控 安全 Java
Java多线程的使用
Java多线程允许程序同时执行多个任务,提高了系统的整体性能和响应速度。通过创建Thread类或其子类的实例,或使用Runnable接口,Java开发者可以定义并发执行的代码段。多线程在处理复杂任务、资源共享、网络通信等方面具有显著优势,但也需要注意线程安全、同步和死锁等问题。Java提供了丰富的API和工具来处理这些并发问题,使多线程编程更加高效和可靠。
|
2天前
|
API
java-多线程-CountDownLatch(闭锁) CyclicBarrier(栅栏) Semaphore(信号量)-
java-多线程-CountDownLatch(闭锁) CyclicBarrier(栅栏) Semaphore(信号量)-
6 1
|
2天前
|
存储 安全 算法
Java基础19-一文搞懂Java集合类框架,以及常见面试题(二)
Java基础19-一文搞懂Java集合类框架,以及常见面试题(二)
30 8
|
2天前
|
安全 Java 开发工具
Java基础19-一文搞懂Java集合类框架,以及常见面试题(一)
Java基础19-一文搞懂Java集合类框架,以及常见面试题(一)
24 6
|
2天前
|
安全 Java 程序员
Java基础18-一文搞懂Java多线程使用方式、实现原理以及常见面试题(二)
Java基础18-一文搞懂Java多线程使用方式、实现原理以及常见面试题(二)
23 4
|
2天前
|
Java 程序员 调度
Java基础18-一文搞懂Java多线程使用方式、实现原理以及常见面试题(一)
Java基础18-一文搞懂Java多线程使用方式、实现原理以及常见面试题(一)
19 0
Java基础18-一文搞懂Java多线程使用方式、实现原理以及常见面试题(一)
|
2天前
|
存储 缓存 Java
Java基础17-读懂Java IO流和常见面试题(二)
Java基础17-读懂Java IO流和常见面试题(二)
15 0
|
2天前
|
存储 Java Unix
Java基础17-读懂Java IO流和常见面试题(一)
Java基础16-读懂Java IO流和常见面试题(一)
15 0