Java并发基础01. 传统线程技术中创建线程的两种方式

时间:2021-10-09 12:28:36

传统的线程技术中有两种创建线程的方式:一是继承Thread类,并重写run()方法;二是实现Runnable接口,覆盖接口中的run()方法,并把Runnable接口的实现扔给Thread。这两种方式大部分人可能都知道,但是为什么这样玩就可以呢?下面我们来详细分析一下这两种方法的来龙去脉。

1. 揭秘Thread中run()

上面我们看到这两种方式都跟`run()`方法有关,所以我们来看一下`Thread`的源码中`run()`方法到底都干了什么:
```java
@Override
public void run() {
if (target != null) {
target.run();
}
}
```
我们可以看出,`run()`方法中很简单,只有一个`if`语句,如果target不为空就执行target的`run()`方法,否则什么也不干,那么这target到底是何方神圣呢?我们点击进去可以看到:
```java
private Runnable target;
```
原来target就是Runnable接口,我们再点进Runnable看看:
```java
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
```
Runnable中就一个方法,也是`run()`方法!好了,现在再回到Thread类的`run()`方法中,如果target不为空,即实现了Runnable接口,也即实现了Runnable中的`run()`方法,那么我们就使用该接口中的`run()`方法;如果target为空,即没有实现Runnable接口,那我们什么也不做,即线程创建后立马就消失了。
所以到这里,大家就明白了为什么创建线程有上面两种方式了。第一种:你不是要先进行`if`判断么?我现在不判断了,我把你的`if`干掉,我在`run()`方法中自己写代码,想干啥就干啥,即重写Thread中的`run()`方法,;第二种:你不是要先进行`if`判断么?行,给你一个Runnable接口让你判断,但你还是得调用我Runnable中的`run()`方法啊,那我重写我Runnable中的`run()`方法不就行了!  
知道了来龙去脉后,下面就针对这两种传统的方式写个实例。

2. 创建方式1:继承Thread类

只要两步即可创建并开启一个线程:

  • 继承Thread类,并实现run()方法;
  • 调用start()方法开启线程。

由于只要实现一个run()方法即可,所以我们可以使用java中的匿名内部类来实现,如下:

public class TraditionalThread {

	public static void main(String[] args) {

		/********** 第一种方法:继承Thread类,覆写run()方法 **************/
Thread thread1 = new Thread(){ @Override
public void run() {
try {
Thread.sleep(500);//让线程休息500毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());//打印出当前线程名
}
};
thread1.start();//开启线程
}
}

3. 创建方式2:实现Runnable接口

只要两步即可创建并开启一个线程:

  • 实现Runnable接口,并实现run()方法;
  • 调用start()方法开启线程。

由于只要实现一个run()方法即可,所以我们也可以使用java中的匿名内部类来实现,如下:

public class TraditionalThread {

	public static void main(String[] args) {

		/********** 第二种方法:实现Runnable接口,扔给Thread **************/
Thread thread2 = new Thread(new Runnable() { @Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()); }
});
thread2.start();
}
}

4. 两种方式同时使用

如果有个哥们比较给力,他两种方式同时使用了,即:既实现了Thread类中的`run()`方法,又给Thread扔了一个实现了`run()`方法的Runnable。如下所示:
```java
public class TraditionalThread {

public static void main(String[] args) {
//这哥们的代码写的比较给力
new Thread(new Runnable() { @Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Runnable:" + Thread.currentThread().getName());
}
}){ @Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread:" + Thread.currentThread().getName());
} }.start();
}

}

现在又会执行哪个呢?我们运行一下上面的程序就会发现,它会打印出Thread的信息,所以运行的是Thread的`run()`方法,知道结论了,但是为啥呢?
从面向对象的思想去考虑:上面一段代码其实是新new了一个对象(子对象)继承了Thread对象(父对象),在子对象里重写了父类的`run()`方法,父对象中扔了个Runnable进去,父对象中的`run()`方法就是最初的带有`if`判断的`run()`方法。
好了,现在执行`start()`后,肯定先在子类中找`run()`方法,找到了,父类的`run()`方法自然就被干掉了,所以会打印出Thread:,如果我们现在假设子类中没有重写`run()`方法,那么必然要去父类找`run()`方法,父类的`run()`方法中就得判断是否有Runnable传进来,现在有一个,所以执行Runnable中的`run()`方法,那么就会打印Runnable:出来。
  
OK,传统的创建线程的两种方式就总结这么多~如有错误之处,欢迎留言指正~

Java并发基础01. 传统线程技术中创建线程的两种方式的更多相关文章

  1. 【java并发】传统线程技术中创建线程的两种方式

    传统的线程技术中有两种创建线程的方式:一是继承Thread类,并重写run()方法:二是实现Runnable接口,覆盖接口中的run()方法,并把Runnable接口的实现扔给Thread.这两种方式 ...

  2. Java中创建String的两种方式

    1.在Java中,创建一个字符串有两种方式 String x = "abc";String y = new String("abc"); 这两种方式有什么区别呢 ...

  3. java中创建字符串的两种方式(“”与new String())及区别

    结论:通过""创建的字符串实际上在java堆中只有一个,而通过new string创建出来的字符串在java堆中占有不同的内存. 第一个True表明这两个在内存中拥有相同的地址,那 ...

  4. Java中创建String的两种方式差异

    我们知道创建一个String类型的变量一般有以下两种方法: String str1 = "abcd"; String str2 = new String("abcd&qu ...

  5. Java中HashMap遍历的两种方式

    Java中HashMap遍历的两种方式 转]Java中HashMap遍历的两种方式原文地址: http://www.javaweb.cc/language/java/032291.shtml 第一种: ...

  6. java中数组复制的两种方式

    在java中数组复制有两种方式: 一:System.arraycopy(原数组,开始copy的下标,存放copy内容的数组,开始存放的下标,需要copy的长度); 这个方法需要先创建一个空的存放cop ...

  7. jQuery中开发插件的两种方式

    jQuery中开发插件的两种方式(附Demo) 做web开发的基本上都会用到jQuery,jQuery插件开发两种方式:一种是类扩展的方式开发插件,jQuery添加新的全局函数(jQuery的全局函数 ...

  8. mybatis中批量插入的两种方式(高效插入)

    MyBatis简介 MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装.MyBatis可以使用 ...

  9. linux内核分析作业4:使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

    系统调用:库函数封装了系统调用,通过库函数和系统调用打交道 用户态:低级别执行状态,代码的掌控范围会受到限制. 内核态:高执行级别,代码可移植性特权指令,访问任意物理地址 为什么划分级别:如果全部特权 ...

随机推荐

  1. Html5离线缓存详细讲解

    离线缓存是Html5新特性之一,简单理解就是第一次加载后将数据缓存,在没有清除缓存前提下,下一次没有网络也可以加载,用在静态数据的网页或游戏比较好用.当然,Html5新的特性都不是所有浏览器都能支持的 ...

  2. GA代码中的细节

    GA-BLX交叉-Gaussion变异 中的代码细节: 我写了一个GA的代码,在2005测试函数上一直不能得到与实验室其他同学类似的数量级的结果.现在参考其他同学的代码,发现至少有如下问题: 1.在交 ...

  3. MySql绿色版应用

    一.配置MySQL数据库 1.解压绿色版mysql,并改名为mysql5.7,如下图 对比一下下图5.6以前的版本,少data目录(存放数据)和my-default.ini文件(配置信息) 二.安装服 ...

  4. 基于VMware Workstation在Windows Server 2008 R2上搭建SQL Server 2012高可用性组(AlwaysOn Group)测试环境(二)

    接上篇: 以SERVER02为例,将服务器加入域,并安装故障转移群集:(SERVER02-SERVER-04操作相同)

  5. 精通Docker的50个必备教程、工具、资源

    Docker 已经震惊了软件开发界.它提供了一种根据 DevOps 方法打包和输送应用程序的便捷方法. 最近我们发布了 51 个必备的 Docker 工具列表①,但工具不是完全精通容器化所需的唯一东西 ...

  6. Python学习---JSON补充内容[中文编码 + dumps解析]

    JSON补充内容[微信解决中文乱码,接上] import json # 英文显示 dic = {"hello": "world"} str = json.dum ...

  7. The adidas NMD Singapore is one of the brands top selling

    Like pointed out, we've two adidas NMD Singapore releases using the first arriving Blue and Black as ...

  8. CC1150 针对低功耗无线应用设计的高度集成多通道射频发送器

    Low Power Sub-1 GHz RF Transmitter 单片低成本低能耗 RF 发送芯片 应用 极低功率 UHF 无线发送器 315/433/868 和 915MHz ISM/SRD 波 ...

  9. Shiro配置cookie以及共享Session和Session失效问题

    首先我们看Shiro的会话管理器的配置 <!-- shiro会话管理 --> <!-- 即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中:会话可以是普通 JavaSE ...

  10. UTF-8 与 BIG-5 转码

    BIG-5 轉 UTF-8 若要將一個文字檔從 BIG-5 編碼轉換為 UTF-8 編碼,可以執行: iconv -f BIG-5 -t UTF-8 big5.txt > utf8.txt 其中 ...