关于线程的创建,其实我一直都有话说,于是今天,我来开个头。今天依旧一样,长话短说,只谈创建多线程。你好,我是fntp!今天要跟大家分享的是博主最近面试Java实习所遇到的一些问题!那就是经常性被问到的多线程!今天是多线程的第一个核心,也是较为轻松的一个话题,我们先来讨论一下,Java实现多线程,究竟有多少种方法。

在Java中实现线程的方式有几种呢?两种?三种?四种?五种?甚至更多?其实都不对。说两种的同学有可能还在JavaSE的苦海中挣扎,忘不了继承Thread类与实现Runnable接口的情感纷争,说是三种的同学,学的还算可以,还没忘记Callable接口与Future,JDK1.5之后的新的API也就是Future,说是四种的兄弟可能说还有线程池ThreadPool的方式,也可能还会有人说,还有TimerThread等等,而我想告诉大家的是,新建线程的方式…其实我跟你讲,你不要告诉别人,其实Java创建线程只有一种方式!没错,只有一种

我们都知道,Java是一门支持多线程的性能优良的语言,并且Java 语言为开发者提供了并发机制,允许开发人员在程序中创建并执行多个线程,每个线程可完成一个功能一个功能可实现一个或多个任务,并与其他线程并发执行。我们说,这种机制就是多线程。

创建多线程的方式看似有很多种,继承Thread类,实现Runnable接口,实现Callable接口,调用ExcutorService任务解释器装载进入线程池等等,在JDK中又实现了对Thread的新的封装引用,又出现新的创建多线程的方式,比如TimerThread定时任务线程等。

乍一看确实创建线程的方式有多种多样,但是本质上,只有一种,那就是构造Thread类。我知道这种回答,可能会让众多CSDN的C友直呼震惊啊!

所谓构造Thread类就是多态的理解,父类类型的对象指向子类类型的引用。说大白话就是继承Thread类,基于此种方式实现多线程。我相信你肯定会说凭什么,凭什么只有这一种方式去实现多线程。我们一起来看看吧。

首先,你得必须知道线程的六大生命周期!

(1)NEW状态。

也称之为 新建状态,很简单理解,就是你New了一个Thread的子类,或者是Runnable的实现类。

(2)Runnable状态。

这是在调用Start()方法之后的Runnable状态,你翻译一下,Runnable,是一个形容词,看看人家用词描述的严谨程度,描述状态名词使用形容词,也就是可运行的,注意是可运行的,运行了吗?没有!是说你有运行的资格,但是并没有运行!所以不是运行状态!

(3)BLOCKED阻塞状态。

BLOCKED是指受阻塞并且正在等待监视器锁的某一线程的线程状态。什么情况下会触发这个状态?最直接的IO操作,计算机中人机交互永远都离不开Input与Output,IO操作的时候,大概率会触发阻塞状态。最常见就是qq与微信同时启动,再开一个谷歌浏览器,这个时候你Win+E你看看你电脑卡不卡就完了,在代码中去理解就是,代码执行,阻塞发生,在该操作return之前,线程不会继续此线程下面的代码。或者是你调用了Sleep()方法,这个是比较常见的一种阻塞。好了,这就是阻塞。

(4)WAITING状态。

这个也有一些比较常见的场景,比如,线程因为调用了Object.wait()或Thread.join()而未运行,就会进入WAITING状态。

(5)TIMED_WAITING状态。

具有指定等待时间的某一等待线程的线程状态。

(6)TERMINATED状态。

线程被终止了或者是,注意,是或者是线程终止了。也就是终止状态。终止状态对应两种不同的情况,一种是自动终止,这是由操作系统所分配的时间片决定的,一种是强制终止,这是用户决定的。至于先终止哪一个需要根据时间片轮转定义以及优先级决定。

好了,知道这些基础知识后,我们就可以来分析一下,为什么Java创建多线程只有一种方式了。我们先看实现Runnable接口:

package com.sinsy.fntp.thread;
public class ThreadTest {/*** fntp* @param args*/public static void main(String[] args) {//创建第一个线程Thread thread01_main = new Thread (new RunnableImplTest ());System.out.println ("执行thread01");thread01_main.start ();//创建第二个线程Thread thread02_main = new Thread ();System.out.println ("执行thread02线程");thread02_main.start ();}}
class RunnableImplTest implements Runnable{@Overridepublic void run() {//实现Runnable接口必须也要重写方法 重写是指覆盖原方法System.out.println ("我执行啦!");//当前正在执行的是哪个Java类?查一下asr ();}public void asr(){System.out.println (Thread.currentThread ().getStackTrace ()[0].getClassName ());}
}

首先我们说,第一种最常见的就是实现Runnable接口, 新建一个Java类实现 Runnable 接口,然后重写该接口的 run() 方法,之后只需要把这个实现了 接口并重写了run() 方法的接口实现类的实例,也就是实现类的对象,作为方法参数传到 Thread 类中就完成了实现多线程的目的。我们先留意一点,实现Runnable,其核心在于哪里?在于我们可以将这个实现类的实例作为方法参数传递到Thread类中来执行。那么,我想问你的是,它本身是一个线程吗?不是吧,对吧,如果接口实现类本身是一个线程,我们前面刚刚介绍的,启动线程直接调用start方法不就可以了吗,你看看Runnable接口实现类有这个方法吗?

答案是肯定没有的,因为Runnable中没有这个方法,这个方法是来自于Thread类才独有的。

所以我们很容易就能想到,执行Run方法是Thread去执行的,那么,好接下来第二个问题,我们将接口实现类传递进入之后干什么用呢?我们不妨先看这张图:发现端倪了吗?不假!Thread是实现了Runnable接口,好家伙,人家Runnable的实现类对象实例都传递给你做老婆了,哦不,是传递给你做参数了,你还不知足,还包‘二奶’?真的是Thread包二奶吗?我们继续往下看:

既然你也实现了人家Runnable接口,你也得对人家负责啊,所以你也得重写run方法吧,否则你就是一个渣男,那么,Thread是不是脚踩两只船呢?包二奶了吗?咳咳预知后事如何,且看…我呸,且看如下代码:

我们发现哈,原来啊!Thread没有不负责,他切实有实现他的run方法哈,那么target是什么鬼呢?我们接着看:

哦,target是他的成员变量,是Runnable类型的对象,接着看:

这块还有一个方法,用来设置Thread类的参数,这块也有target,哈哈,离真相不远了…

哎呀,真相大白了,target在这里进行赋值,也就是说,Thread将传递来的参数,这个参数是通过new产生的,必然会在堆区中生成地址,Thread通过这个构造方法,将堆区中的地址引过来赋值给了本地成员属性,因此啊!Thread没有脚踩两只船,更没有包二奶,而是直接将传递来的参数接口实现类对象直接拿来,让他去调用Run方法,嗦嘎,这不就是妙蛙种子吃了妙脆角进了米奇妙妙屋,妙到家了吗?明白了吧,好的,原来,实现Runnable接口只是为了两个目的,第一,将实现了接口的实现类的对象作为参数传递到thread类中,然后呢,构造Thread对象,然后通过thread类的start方法去启动多线程!好家伙,整半天,实现Runnable接口就是为了告诉Thread应该做什么,而启动Thread还得依靠Thread本身!毕竟啊,start方法只有Thread有啊!好家伙,现实版做自己的贵人啊!

那么:线程池呢?

关于线程池,我们都知道,对于线程池而言,本质上是通过线程工厂创建线程的,默认采用 DefaultThreadFactory ,这个Java类在执行构造方法的时候,会给线程参数传递一些线程的默认参数,比如:Thread_Name线程的名字、设置为守护线程与否,以及设置初始化线程的优先级等。但是无论怎么设置这些属性,最终它还是通过 new Thread() 创建线程的。这也就是为什么说,线程池同样,也是属于一种创建线程的方式之一,因为其底层到最后都是通过new Thread类的方式来构建线程对象,从而来创建,启动和操作线程的。

最后,我们来简单说一下Callable吧,其实不说你也知道了,你肯定清楚,通过Callable 创建线程,与Runnable相比,Runnable是无返回值的,而 Callable 和与之相关的 Future、FutureTask是有返回值的,它们可以把线程执行的结果作为返回值返回。这也是他们之间的一些明显的区别。

然并卵,无论是 Callable 还是 FutureTask,它们首先和 Runnable 一样,都是一个任务,你会发现,在ExcutorService中,依旧可以将Runnable实现类作为参数传递进入执行,这也就印证了Runnable与Callable都是需要被执行的任务而已,它们本身就不是线程。但是可以将它们放到线程池中去执行,可以通过 submit() 方法把任务放到线程池中,并由线程池创建线程,不管用什么方法,最终都是靠线程来执行的,而线程的创建方式仍脱离不了这一种方式,也就是继承 Thread 类传递任务参数,最终使用该类的start方法来启动多线程。所以,我想知道的是,你明白了吗?

Java面试之多线程:Java创建多线程为什么只有一种方式?相关推荐

  1. 【多线程】创建线程池有几种方式

    网上的文章一般会说,创建线程池基本上是2种方式.ThreadPoolExecutor或者Executors.本文就是通过剖析源码,看下它们的实现. ThreadPoolExecutor ThreadP ...

  2. 视频教程-Java面试Offer直通车-Java

    Java面试Offer直通车 10年大厂工作经验,有IBM,花旗,平安等一线外企和互联网工作经验,8年Java面试官经验,了解面试java初级开发高级开发和架构师的背后一面,更熟悉各种在面试中展示亮点 ...

  3. 【转】Java面试资源----百度Java面试题前200页大汇总

    基本概念 操作系统中 heap 和 stack 的区别 什么是基于注解的切面实现 什么是 对象/关系 映射集成模块 什么是 Java 的反射机制 什么是 ACID BS与CS的联系与区别 Cookie ...

  4. Java 创建一个线程的三种方式

    Java 创建一个线程的三种方式 更多内容,点击了解: https://how2j.cn/k/thread/thread-start/353.html 创建多线程有3种方式,分别是继承线程类,实现Ru ...

  5. java如何创造一个整数的类_【技术干货】Java 面试宝典:Java 基础部分(1)

    原标题:[技术干货]Java 面试宝典:Java 基础部分(1) Java基础部分: 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语法,集合的语法,io 的 ...

  6. java class 生成对象_Java反射机制(创建Class对象的三种方式)

    1:SUN提供的反射机制的类: java.lang.Class java.lang.reflect.Constructor java.lang.reflect.Field java.lang.refl ...

  7. python创建多线程_Python 多线程,threading模块,创建子线程的两种方式示例

    本文实例讲述了Python 多线程,threading模块,创建子线程的两种方式.分享给大家供大家参考,具体如下: GIL(全局解释器锁)是C语言版本的Python解释器中专有的,GIL的存在让多线程 ...

  8. java创建线程池几种方式_java知识总结-创建线程池的6种方式

    一.创建线程池的6种方式: Executors.newCachedThreadPool(); 创建一个可缓存线程池,应用中存在的线程数可以无限大 Executors.newFixedThreadPoo ...

  9. java解析遍历List集合(其实现子类)的三种方式

    java解析遍历List集合(其实现子类)的三种方式 1 使用迭代器对象 1.1 底层 1.1.1 List接口继承了Collection接口 1.1.2 而Collection接口又继承了Itera ...

  10. 线程池的五种状态及创建线程池的几种方式

    上篇<Java线程的6种状态详解及创建线程的4种方式> 前言:我们都知道,线程是稀有资源,系统频繁创建会很大程度上影响服务器的使用效率,如果不加以限制,很容易就会把服务器资源耗尽.所以,我 ...

最新文章

  1. dplyr和data.table让你的数据分析事半功倍
  2. AI:2020年WAIC世界人工智能大会2020年7月9日9:30-12:00开幕式《李彦宏、Elon Musk、马云等大佬演讲》
  3. 2022年全球及中国工业用真空电缆行业十四五产能需求与投资战略研究报告
  4. 如何快速完成整理笔记?
  5. 思科交换机PXE响应巨慢,甚至无响应问题
  6. 微信小程序开发的入门基础知识点
  7. flutter不支持热更新_真当Flutter不能热更新?众能动态化Flutter
  8. Spring Boot2整合Shiro(1):身份认证
  9. pythondjango是干什么的_python django框架是什么?怎么使用?
  10. python self理解_Python列表理解
  11. python使用 photoshop-python-api 调用ps处理批量动作操作
  12. 在网站优化中怎么做好关键词密度?
  13. 重温C语言 | 指针基础(指针与内存)
  14. PS怎样把成图变成素描或者速写稿
  15. Python基础语法——if选择
  16. 【PaddleHub模型贡献】一行代码实现水表的数字表盘分割
  17. 为什么大家认为中台不能用于传统行业?
  18. 500分能上的计算机院校,高考500分上下怎么选大学?推荐这几所学校
  19. mysql 的delete from 子查询限制
  20. 计算机设置更改被锁定怎么办,处理win7电脑中IE主页一直被锁定修改的问题

热门文章

  1. 简单介绍红白机的发声系统以及其它音源 MMC
  2. ssm与springboot常见注解
  3. XPosed及插件安装(解决下载http://dl.xposed.info/repo/full.xml.gz时出错的问题)
  4. AM5728调试经历(2)
  5. 关于运算放大器电流流向的问题
  6. web编程开发_Web编程简介(Web设计和Web开发)
  7. java 返回类对象_JAVA如何实现返回不同类型的对象
  8. 线性模型(梯度下降随机梯度下降)
  9. 美丽的小丑,谁的悲哀
  10. 京东到家订单订单查询服务演进