Java 高级应用-多线程-(一)实现 Runnable 接口与继承 Thread 类

这篇具有很好参考价值的文章主要介绍了Java 高级应用-多线程-(一)实现 Runnable 接口与继承 Thread 类。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.1 程序、进程与线程
• 程序(program):为完成特定任务,用某种语言编写的一组指令的集合。即指一段
静态的代码,静态对象。
• 进程(process):程序的一次执行过程,或是正在内存中运行的应用程序。如:运行
中的 QQ,运行中的网易音乐播放器。
– 每个进程都有一个独立的内存空间,系统运行一个程序即是一个进程从创
建、运行到消亡的过程。(生命周期)
– 程序是静态的,进程是动态的
– 进程作为操作系统调度和分配资源的最小单位(亦是系统运行程序的基
本单位),系统在运行时会为每个进程分配不同的内存区域。
– 现代的操作系统,大都是支持多进程的,支持同时运行多个程序。比如:
现在我们上课一边使用编辑器,一边使用录屏软件,同时还开着画图板,
dos 窗口等软件。
• 线程(thread):进程可进一步细化为线程,是程序内部的一条执行路径。
一 个进程中至少有一个线程。
– 一个进程同一时间若并行执行多个线程,就是支持多线程的。
Java 高级应用-多线程-(一)实现 Runnable 接口与继承 Thread 类

– 线程作为 CPU 调度和执行的最小单位。
– 一个进程中的多个线程共享相同的内存单元,它们从同一个堆中分配对
象,可以访问相同的变量和对象。这就使得线程间通信更简便、高效。但
多个线程操作共享的系统资源可能就会带来安全的隐患。
– 下图中,红框的蓝色区域为线程独享,黄色区域为线程共享。

Java 高级应用-多线程-(一)实现 Runnable 接口与继承 Thread 类

注意:
不同的进程之间是不共享内存的。
进程之间的数据交换和通信的成本很高。

1.5.2 并行与并发
• 并行(parallel):指两个或多个事件在同一时刻发生(同时发生)。
指在同一时刻,有多条指令在多个 CPU 上同时执行。比如:多个人同时做不同的事。
Java 高级应用-多线程-(一)实现 Runnable 接口与继承 Thread 类

**• 并发(concurrency):指两个或多个事件在同一个时间段内发生。**即在一段时间内,有多条指令在单个 CPU 上快速轮换、交替执行,使得在宏观上具有多个进程同时执行的效果。
Java 高级应用-多线程-(一)实现 Runnable 接口与继承 Thread 类

2.创建和启动线程
2.1 概述
• Java 语言的 JVM 允许程序运行多个线程,使用 java.lang.Thread 类代表线程,所
有的线程对象都必须是 Thread 类或其子类的实例。
• Thread 类的特性
– 每个线程都是通过某个特定 Thread 对象的 run()方法来完成操作的,因此
把 run()方法体称为线程执行体。
– 通过该 Thread 对象的 start()方法来启动这个线程,而非直接调用 run()
– 要想实现多线程,必须在主线程中创建新的线程对象。

2.2 方式 1:继承 Thread 类

Java 通过继承 Thread 类来创建并启动多线程的步骤如下:

  1. 定义 Thread 类的子类,并重写该类的 run()方法,该 run()方法的方法体就代表了线程
    需要完成的任务
  2. 创建 Thread 子类的实例,即创建了线程对象
  3. 调用线程对象的 start()方法来启动该线程
    代码如下:
package com.atguigu.thread;
//自定义线程类
public class MyThread extends Thread {
 //定义指定线程名称的构造方法
 public MyThread(String name) {
 //调用父类的 String 参数的构造方法,指定线程的名称
 super(name);
 }
 /**
 * 重写 run 方法,完成该线程执行的逻辑
 */
 @Override
 public void run() {
 for (int i = 0; i < 10; i++) {
 System.out.println(getName()+":正在执行!"+i);
 }
 }
}

测试类:


package com.atguigu.thread;
public class TestMyThread {
 public static void main(String[] args) {
 //创建自定义线程对象 1
 MyThread mt1 = new MyThread("子线程 1");
 //开启子线程 1
 mt1.start();
 
 //创建自定义线程对象 2
 MyThread mt2 = new MyThread("子线程 2");
 //开启子线程 2
 mt2.start();
 
 //在主方法中执行 for 循环
 for (int i = 0; i < 10; i++) {
 System.out.println("main 线程!"+i);
 }
 }
}

Java 高级应用-多线程-(一)实现 Runnable 接口与继承 Thread 类
注意:

1.如果自己手动调用 run()方法,那么就只是普通方法,没有启动多线程模 式。
2.run()方法由 JVM 调用,什么时候调用,执行的过程控制都有操作系统的 CPU 调度决定。
3.想要启动多线程,必须调用 start 方法。
4.一个线程对象只能调用一次 start()方法启动,如果重复调用了,则将抛出 以上的异常“IllegalThreadStateException”。

2.3 方式 2:实现 Runnable 接口

Java 有单继承的限制,当我们无法继承 Thread 类时,那么该如何做呢?在核心
类库中提供了 Runnable 接口,我们可以实现 Runnable 接口,重写 run()方法,
然后再通过 Thread 类的对象代理启动和执行我们的线程体 run()方法

步骤如下:
2. 定义 Runnable 接口的实现类,并重写该接口的 run()方法,该 run()方法的方法体同样是该线程的线程执行体。
3. 创建 Runnable 实现类的实例,并以此实例作为 Thread 的 target 参数来创建Thread 对象,该 Thread 对象才是真正 的线程对象。
4. 调用线程对象的 start()方法,启动线程。调用 Runnable 接口实现类的run 方法。
代码如下:

package com.atguigu.thread;
public class MyRunnable implements Runnable {
 @Override
 public void run() {
 for (int i = 0; i < 20; i++) {
 System.out.println(Thread.currentThread().getName() + " "
+ i);
 }
 }
}

测试类:

package com.atguigu.thread;
public class TestMyRunnable {
 public static void main(String[] args) {
 //创建自定义类对象 线程任务对象
 MyRunnable mr = new MyRunnable();
 //创建线程对象
 Thread t = new Thread(mr, "长江");
 t.start();
 for (int i = 0; i < 20; i++) {
 System.out.println("黄河 " + i);
 }
 }
}

通过实现 Runnable 接口,使得该类有了多线程类的特征。所有的分线程要执行的代码都在 run 方法里面。
在启动的多线程的时候,需要先通过 Thread 类的构造方法 Thread(Runnable target) 构造出对象,然后调用 Thread 对象的 start()方法来运行多线程代码。
实际上,所有的多线程代码都是通过运行 Thread 的 start()方法来运行的。因此,不管是继承 Thread 类还是实现 Runnable 接口来实现多线程,最终还是通过 Thread 的对象的 API 来控制线程的,熟悉 Thread 类的 API 是进行多线程编程的基础。

说明:Runnable 对象仅仅作为 Thread 对象的 target,Runnable 实现类里包含的 run()方法仅作为线程执行体。
而实际的线程对象依然是 Thread 实例,只是该 Thread 线程负责执行其 target 的 run()方法。

2.5 对比两种方式

联系

Thread 类实际上也是实现了 Runnable 接口的类。即: public class Thread extends Object implements Runnable

区别

• 继承 Thread:线程代码存放 Thread 子类 run 方法中。
• 实现 Runnable:线程代码存在接口的子类的 run 方法。

实现 Runnable 接口比继承 Thread 类所具有的优势

• 避免了单继承的局限性
• 多个线程可以共享同一个接口实现类的对象,非常适合多个相同线程来处理同一份资 源。
•增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。

3. Thread 类的常用结构
3.1 构造器

public Thread() :分配一个新的线程对象。
• public Thread(String name) :分配一个指定名字的新的线程对象。
• public Thread(Runnable target) :指定创建线程的目标对象,它实现了 

Runnable 接口中的 run 方法

public Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字。

3.2 常用方法系列 1

public void run() :此线程要执行的任务在此处定义代码。
• public void start() :导致此线程开始执行; Java 虚拟机调用此线程的 run 方法。
• public String getName() :获取当前线程名称。
• public void setName(String name):设置该线程名称。
• public static Thread currentThread() :返回对当前正在执行的线程对象的引用。在
Thread 子类中就是 this,通常用于主线程和 Runnable 实现类
• public static void sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停(暂时
停止执行)。
• public static void yield()yield 只是让当前线程暂停一下,让系统的线程调度器重新
调度一次,希望优先级与当前线程相同或更高的其他线程能够获得执行机会,但是这
个不能保证,完全有可能的情况是,当某个线程调用了 yield 方法暂停之后,线程调
度器又将其调度出来重新执行。

4.1 JDK1.5 之前:5 种状态
线程的生命周期有五种状态:新建(New)、就绪(Runnable)、运行
(Running)、阻塞(Blocked)、死亡(Dead)。
CPU 需要在多条线程之间切
换,于是线程状态会多次在运行、阻塞、就绪之间切换

Java 高级应用-多线程-(一)实现 Runnable 接口与继承 Thread 类
1.新建
当一个 Thread 类或其子类的对象被声明并创建时,新生的线程对象处于新建状
态。此时它和其他 Java 对象一样,仅仅由 JVM 为其分配了内存,并初始化了
实例变量的值。此时的线程对象并没有任何线程的动态特征,程序也不会执行
它的线程体 run()。
2.就绪
但是当线程对象调用了 start()方法之后,就不一样了,线程就从新建状态转为
就绪状态。JVM 会为其创建方法调用栈和程序计数器,当然,处于这个状态中
的线程并没有开始运行,只是表示已具备了运行的条件,随时可以被调度。至
于什么时候被调度,取决于 JVM 里线程调度器的调度。
注意:
程序只能对新建状态的线程调用 start(),并且只能调用一次,如果对
非新建状态的线程,如已启动的线程或已死亡的线程调用 start()都会
报错 IllegalThreadStateException 异常。
3.运行
如果处于就绪状态的线程获得了 CPU 资源时,开始执行 run()方法的线程体代
码,则该线程处于运行状态。如果计算机只有一个 CPU 核心,在任何时刻只有
一个线程处于运行状态,如果计算机有多个核心,将会有多个线程并行
(Parallel)执行。
当然,美好的时光总是短暂的,而且 CPU 讲究雨露均沾。对于抢占式策略的系
统而言,系统会给每个可执行的线程一个小时间段来处理任务,当该时间用
完,系统会剥夺该线程所占用的资源,让其回到就绪状态等待下一次被调度。
此时其他线程将获得执行机会,而在选择下一个线程时,系统会适当考虑线程
的优先级。
4.阻塞
当在运行过程中的线程遇到如下情况时,会让出 CPU 并临时中止自己的执
行,进入阻塞状态:
• 线程调用了 sleep()方法,主动放弃所占用的 CPU 资源;
• 线程试图获取一个同步监视器,但该同步监视器正被其他线程持有;
• 线程执行过程中,同步监视器调用了 wait(),让它等待某个通知(notify);
• 线程执行过程中,同步监视器调用了 wait(time)
• 线程执行过程中,遇到了其他线程对象的加塞(join);
• 线程被调用 suspend 方法被挂起(已过时,因为容易发生死锁);
当前正在执行的线程被阻塞后,其他线程就有机会执行了。针对如上情况,当
发生如下情况时会解除阻塞,让该线程重新进入就绪状态,等待线程调度器再
次调度它:
• 线程的 sleep()时间到;
• 线程成功获得了同步监视器;
• 线程等到了通知(notify);
• 线程 wait 的时间到了
• 加塞的线程结束了;
• 被挂起的线程又被调用了 resume 恢复方法(已过时,因为容易发生死锁);
5.死亡
线程会以以下三种方式之一结束,结束后的线程就处于死亡状态:
• run()方法执行完成,线程正常结束
• 线程执行过程中抛出了一个未捕获的异常(Exception)或错误(Error)
• 直接调用该线程的 stop()来结束该线程(已过时)

4.2 JDK1.5 及之后:6 种状态
在 java.lang.Thread.State 的枚举类中这样定义:
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
• NEW(新建):线程刚被创建,但是并未启动。还没调用 start 方法。
• RUNNABLE(可运行):这里没有区分就绪和运行状态。因为对于 Java 对象来说,只
能标记为可运行,至于什么时候运行,不是 JVM 来控制的了,是 OS 来进行调度的,
而且时间非常短暂,因此对于 Java 对象的状态来说,无法区分。
• Teminated(被终止):表明此线程已经结束生命周期,终止运行。
• 重点说明,根据 Thread.State 的定义,阻塞状态分为三种:BLOCKED、WAITING、
TIMED_WAITING。
– BLOCKED(锁阻塞):在 API 中的介绍为:一个正在阻塞、等待一个监视
器锁(锁对象)的线程处于这一状态。只有获得锁对象的线程才能有执行
机会。
• 比如,线程 A 与线程 B 代码中使用同一锁,如果线程 A 获取到
锁,线程 A 进入到 Runnable 状态,那么线程 B 就进入到 Blocked
锁阻塞状态。
– TIMED_WAITING(计时等待):在 API 中的介绍为:一个正在限时等待
另一个线程执行一个(唤醒)动作的线程处于这一状态。
• 当前线程执行过程中遇到 Thread 类的 sleep 或 join,Object 类
的 wait,LockSupport 类的 park 方法,并且在调用这些方法时,
设置了时间,那么当前线程会进入 TIMED_WAITING,直到时间
到,或被中断。
– WAITING(无限等待):在 API 中介绍为:一个正在无限期等待另一个线
程执行一个特别的(唤醒)动作的线程处于这一状态。
• 当前线程执行过程中遇到遇到 Object 类的 wait,Thread 类的
join,LockSupport 类的 park 方法,并且在调用这些方法时,没
有指定时间,那么当前线程会进入 WAITING 状态,直到被唤醒。
– 通过 Object 类的 wait 进入 WAITING 状态的要有 Object 的
notify/notifyAll 唤醒;
– 通过 Condition 的 await 进入 WAITING 状态的要有
Condition 的 signal 方法唤醒;
– 通过 LockSupport 类的 park 方法进入 WAITING 状态的要有
LockSupport 类的 unpark 方法唤醒
– 通过 Thread 类的 join 进入 WAITING 状态,只有调用 join
方法的线程对象结束才能让当前线程恢复;
说明:当从 WAITING 或 TIMED_WAITING 恢复到 Runnable 状态时,如果发现
当前线程没有得到监视器锁,那么会立刻转入 BLOCKED 状态。

Java 高级应用-多线程-(一)实现 Runnable 接口与继承 Thread 类
OR
Java 高级应用-多线程-(一)实现 Runnable 接口与继承 Thread 类文章来源地址https://www.toymoban.com/news/detail-474507.html

到了这里,关于Java 高级应用-多线程-(一)实现 Runnable 接口与继承 Thread 类的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java 高级应用-多线程-(四)FutureTask的介绍及使用

    Java多线程之FutureTask的介绍及使用 FutureTask属于java.util.concurrent 包;FutureTask表示可取消的异步计算。FutureTask类提供了一个Future的基本实现 ,具有启动和取消计算的方法,查询计算是否完整,并检索计算结果。结果只能在计算完成后才能检索; 如果计算尚未完成,则get方法将阻

    2024年02月07日
    浏览(35)
  • javafx应用程序线程异常Exception in thread “JavaFx Application Thread“

    前几天用javafx做小桌面应用程序出现了一个问题: 反复检查,最终确定报错的原因是UI刷新频率过快导致的 javafx提供了Platform.runLater用于解决该问题:  总结:需要高频调用方法使用Platform.runLater

    2024年02月10日
    浏览(50)
  • Autofac高级应用,一个接口多个实现类如何注册到容器并获取实例

      当使用Autofac处理一个接口有多个实现的情况时, 通常会使用键(key)进行区分 或者 通过IIndex索引注入 ,也可以 通过IEnumerable集合获取所有实例 ,以下是一个具体的例子,演示如何在Autofac中注册多个实现,并通过构造函数注入获取指定实现。 首先,确保你已经安装了A

    2024年02月05日
    浏览(50)
  • 【STM32&RT-Thread零基础入门】 7. 线程创建应用(多线程运行机制)

    硬件:STM32F103ZET6、ST-LINK、usb转串口工具、4个LED灯、1个蜂鸣器、4个1k电阻、2个按键、面包板、杜邦线 本章进一步研究多线程的运行机制。要求实现功能如下:创建2个线程,线程名称分别为LED和BEEP。两个线程的任务是连续5次打印本线程的名字后退出线程(注意:线程不执行

    2024年02月03日
    浏览(37)
  • Java多线程---线程的创建(Thread类的基本使用)

    本文主要介绍Java多线程的相关知识, Thread的创建, 常用方法的介绍和使用, 线程状态等. 文章目录 前言 一. 线程和Thread类 1. 线程和Thread类 1.1 Thread类的构造方法 1.2 启用线程的相关方法 2. 创建第一个Java多线程程序 3. 使用Runnable对象创建线程 4. 使用内部类创建线程 5. 使用Lamba

    2024年02月03日
    浏览(40)
  • Java 线程池(Thread Pools)详解

    目录 1、线程池介绍 2、线程池执行原理 3、线程池中的阻塞队列 4、Java 线程池中的拒绝策略 5、Java 提供的创建线程池的方式 6、线程池的使用示例 7、ForkJoinPool 和 ThreadPool 的区别 1、线程池介绍          线程池是一种重用线程的机制 ,用于提高线程的利用率和管理线程的

    2024年02月05日
    浏览(40)
  • 【STM32&RT-Thread零基础入门】 6. 线程创建应用(线程挂起与恢复)

    硬件:STM32F103ZET6、ST-LINK、usb转串口工具、4个LED灯、1个蜂鸣器、4个1k电阻、2个按键、面包板、杜邦线 在上一个任务中,通过停止命令把线程删除后,线程在系统中就不存在了,也无法再使线程重新运行。例如输入stop_led_thread命令后,led停止闪烁,但也无法重新开启LED灯闪烁

    2024年02月11日
    浏览(37)
  • 【JavaEE】Java中的多线程 (Thread类)

    作者主页: paper jie_博客 本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。 本文录入于《JavaEE》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造,将基础知识一网打尽,希望可以帮到读者们哦。 其他专栏:《MySQL》《

    2024年02月05日
    浏览(54)
  • Java多线程 -Thread类的常用API

    Thread常用API说明 : Thread常用方法:获取线程名称getName()、设置名称setName()、获取当前线程对象currentThread()。 至于Thread类提供的诸如:yield、join、interrupt、不推荐的方法 stop 、守护线程、线程优先级等线程的控制方法,在开发中很少使用,这些方法会在高级篇以及后续需要用到

    2024年02月21日
    浏览(49)
  • 【java】【maven】【高级】MAVEN聚合继承属性等

    目录 1、模块开发与设计 2、聚合 2、继承 3、属性 4、版本管理 5、资源配置 6、多环境配置 7、多环境开发配置 8、跳过测试 9、私服  前言:maven的高级使用包含分模块开发与设计、聚合、继承、属性、版本管理、资源配置、多环境配置、多环境开发配置、跳过测试、私服  

    2024年02月13日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包