Java中线程的创建与使用、Thread类的常用方法

news2024/10/7 12:25:19

1、什么是进程与线程

1.1 含义

1.1.1 进程

进程是指正在运行的程序的实例。在操作系统中,一个进程代表了一个正在执行的程序,它包括了程序的代码、数据以及程序执行时所需要的系统资源。

最直观的就是我们任务管理器:

任务管理器中的每一个应用程序都是一个进程。

1.1.2 线程

线程是进程中的一个执行单元。一个进程可以包含多个线程,每个线程都拥有独立的执行路径,可以独立执行特定的任务,一个进程中的所有线程都共享这个进程的资源。

比如下面的这个例子。 进程:餐厅的整个经营过程可以看作一个进程。它包括了所有的资源和活动,例如厨房、餐厅大厅、服务员、厨师、顾客等。 线程:在餐厅中,服务员可以看作是一个线程。有很多个服务员,他们分别负责接待顾客、记录订单、传递菜单、上菜等任务。服务员是餐厅进程中的一个执行单元,他与其他服务员共享同一份资源,如餐厅的桌子、厨房、食材等。多个服务员可以并行执行任务,提高效率。

1.1.3 线程与进程的区别

进程的诞生就是为了实现程序的并发执行。所谓并发,就是在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行。

线程的诞生目的是为了减少程序在并发执行时所付出的时空开销,使操作系统具有更好的并发性。

  • 地址空间:线程共享本进程的地址空间,而进程之间是独立的地址空间。
  • 资源:线程共享本进程的资源如内存、I/O、CPU等,而进程之间的资源是独立的。
  • 健壮性:多进程要比多线程健壮,一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。
  • 执行过程:每个独立的进程有一个程序运行的入口、顺序执行序列和程序出口,执行开销大。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,执行开销小。
  • 可并发性:两者均可并发执行。
  • 切换时:进程切换时,消耗的资源大,效率低。所以涉及到频繁的切换时,使用线程要好于进程。
  • 其他:进程是操作系统资源分配的基本单位,线程是操作系统调度的基本单位。

1.2 PCB与TCB

进程控制块 PCB(Process Control Block),它是用来描述和控制进程的运行的一个数据结构。它是进程存在的唯一标志,也是操作系统管理进程的重要依据。

TCB(Thread Control Block)是线程控制块的缩写,是操作系统中用来描述和控制线程运行的一种数据结构。

它们的关系:

PCB中存储了进程的标识符、状态、优先级、寄存器、程序计数器、堆栈指针、资源清单、同步和通信机制等信息。PCB是进程存在的唯一标志,也是实现进程切换和调度的基础。

TCB与PCB是差不多的,TCB中也存储了线程的标识符、状态、优先级、寄存器、程序计数器、堆栈指针、信号屏蔽等信息。TCB是线程存在的唯一标志,也是实现线程切换和调度的基础。

2.创建线程的几种方式

线程是操作系统中的概念。操作系统内核实现了线程这样的机制,并且对用户层提供了一些 API 供用户使用。Java 标准库中 Thread 类可以视为是对操作系统提供的 API 进行了进一步的抽象和封装。

2.1 继承 Thread 类

(1)继承 Thread 来创建一个线程类。

class MyThread extends Thread{
    //重写run方法,run 表示这个线程需要执行的任务
    @Override
    public void run() {
        System.out.println("这个线程需要执行的任务");
    }
}

(2)创建 MyThread 实例。

//创建一个 MyThread 实例
MyThread myThread = new MyThread();

(3)调用 start() 方法,线程开始执行。

//start 方法表示这个线程开始执行,注意,这里不是调用 run()方法
myThread.start();

2.2 实现 Runnable 接口

(1)实现 Runnable 接口。

//通过 实现 Runnable 接口来创建一个线程
class MyRunnable implements Runnable{

    //需要重写run方法
    @Override
    public void run() {
        System.out.println("这个线程需要执行的任务");
    }
}

(2)创建一个 Thread 实例。

//创建 Thread 类实例, 调用 Thread 的构造方法时将 Runnable 对象作为参数。
Thread thread = new Thread(new MyRunnable());

(3)调用 start() 方法,线程开始执行。

//线程开始运行
thread.start();

2.3 其它变形

  • 匿名内部类创建 Thread 子类对象。
Thread thread1 = new Thread(){
    @Override
    public void run() {
        System.out.println("使用匿名类创建 Thread 子类对象");
    }
};
  • 匿名内部类创建 Runnable 子类对象。
Thread thread2 = new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("使用匿名类创建 Runnable 子类对象");
    }
});
  • lambda 表达式创建 Runnable 子类对象。
Thread thread3 = new Thread(()-> {
    System.out.println("使用匿名类创建 Thread 子类对象");
});

3.Thread 类的常见方法

3.1 Thread 的常见构造方法

方法说明
Thread()创建线程对象
Thread(Runnable target)使用 Runnable 对象创建线程对象
Thread(String name)创建线程对象,并命名
Thread(Runnable target, String name)使用 Runnable 对象创建线程对象,并命名
Thread thread = new Thread("小明"){
    @Override
    public void run(){
        while(true){
        	System.out.println("我是小明");
    	}   
    }
};

这个线程的名字为“小明”,如何查看这个线程的名字呢?在Java开发工具包(JDK) 中,可以使用jconsole来监视线程。

  1. 打开你的 jdk 路径,我这里是C:\Program Files\Java\jdk1.8.0_31\bin,打开该路径下的jconsole工具。
  2. 运行上面的代码,然后根据如下操作:

可以看到有一个叫“小明”的线程,这个就是我们创建的线程。

3.2 获取 Thread 属性的方法

属性获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否后台线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()
  • ID 是线程的唯一标识,不同线程不会重复。
  • 名称是线程的名称。
  • 状态表示线程当前所处的一个情况,比如阻塞、运行等。
  • 优先级高的线程更容易被调度到。
  • 关于后台线程:后台线程(Daemon Thread)是在程序运行过程中在后台提供服务的线程。与前台线程(也称为用户线程)相对,后台线程不会阻止程序的终止。当所有的前台线程(用户线程)结束时,后台线程会自动被终止,即使它们尚未执行完毕。
  • 是否存活,即简单的理解,为 run 方法是否运行结束了。

3.3 启动线程的方法 start()

前文已经演示过了,之前我们已经看到了如何通过重写 run 方法创建一个线程对象,但线程对象被创建出来并不意味着线程就开始运行了。重写 run 方法是提供给线程要做的事情的指令清单。而调用 start() 方法,线程才能真正独立去执行,调用 start 方法, 才真的在操作系统的底层创建出一个线程。

3.4 线程睡眠 sleep()

方法说明
public static void sleep(long millis) throws InterruptedException休眠当前线程 millis 毫秒
public static void sleep(long millis, int nanos) throws InterruptedException可以更高精度的休眠

如下代码:

public static void main(String[] args) throws InterruptedException {
    long begin = System.currentTimeMillis();
    Thread.sleep(3000);//睡眠当前线程
    long end = System.currentTimeMillis();
    System.out.println(end - begin);
}

结果:

它的一些更详细内容后文介绍。

3.5 中断线程

这里的中断不是马上就中断的意思,具体的我们看下面的案例。

这里有两个线程,通过一个线程来中断另一个线程,这里先不使用Thread的方法。

public class Main {
    
    public static volatile boolean flag = true;
    
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(){
            @Override
            public void run(){
                // flag 是中断标记
                while(flag){
                    try {
                        Thread.sleep(500);//睡眠
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("Hi");
                }
            }
        };
        //开启线程
        thread.start();

        //中断线程
        Thread.sleep(3000); //睡眠 3 秒
        flag = false;//更改标记
        System.out.println("开始中断线程");
    }
}

(volatile的作用这里不作介绍,后面会持续更新。)

结果:

你会发现,这里的中断就是改变标记位的值,并且这里是有延迟的,只有sleep睡眠结束的时候才能结束线程。

所以就可以使用Thread提供的方法,即: isInterrupted()或者interrupted(),它们的优点就是能立刻唤醒睡眠的线程,看下面的案例。

方法说明
public void interrupt()中断对象关联的线程,如果线程正在阻塞,则以异常方式通知, 否则设置标志位
public static boolean interrupted()判断当前线程的中断标志位是否设置,调用后清除标志位
public boolean isInterrupted()判断对象关联的线程的标志位是否设置,调用后不清除标志位

这里的标志位的详细介绍在后面。

public static void main(String[] args) throws InterruptedException {

        Thread thread = new Thread(){
            @Override
            public void run(){
                // flag 是中断标记
                while(!Thread.currentThread().isInterrupted()){
                    try {
                        Thread.sleep(500);//随眠
                    } catch (InterruptedException e) {
                        e.printStackTrace();//打印报错信息
                    }
                    System.out.println("Hi");
                }
            }
        };
        //开启线程
        thread.start();

        Thread.sleep(3000); //睡眠 3 秒
        thread.interrupt();//中断 thread 线程,把标记位置为true。
        System.out.println("开始中断线程");
    }

这里解释一下!Thread.currentThread().isInterrupted(),Thread.currentThread()的作用是返回当前线程对象的引用,跟this差不多:

方法说明
public static Thread currentThread();返回当前线程对象的引用

isInterrupted():如果当前线程被中断就返回true,否则返回false。

这里的中断要根据中断标志位来看,中断标志位(interrupt flag)是线程的内部状态之一,实际上是存在于线程的内部数据结构中。**具体来说,中断标志位是线程对象的一个成员变量,用于表示线程的中断状态。**这个标志位在线程创建时被初始化为false,当调用线程的interrupt()方法时,中断标志位会被设置为true,表示线程被中断。

Thread.currentThread().isInterrupted(),这里就表示当前线程是否中断,如果中断就返回true,否则false。最后在前面加上一个!,来作为while的条件,那就是中断就返回false,否则true。

最后我们来看看结果,注意,上面我们已经调用了thread.interrupt(),所以预期是sleep抛异常,然后结束循环(结束线程),

结果:

为什么这里程序没有结束呢?我们来慢慢分析,没结束显然是while循环的条件还是ture,那么Thread.currentThread().isInterrupted()的值就是false,就表示线程不是处于中断状态,What?我们不是已经调用了interrupt()方法了吗?

原因就是:当线程被阻塞时,比如调用了sleep()、join() 或 wait()方法,如果收到了中断请求,这些方法会抛出 InterruptedException 异常,并清除中断状态!,这里的清除中断状态就是把标记位置为false,表示该线程没有被中断。

如果解决这个问题呢?直接在catch中加上break就行了。

public static void main(String[] args) throws InterruptedException {

        Thread thread = new Thread(){
            @Override
            public void run(){
                // flag 是中断标记
                while(!Thread.currentThread().isInterrupted()){
                    try {
                        Thread.sleep(500);//随眠
                    } catch (InterruptedException e) {
                        //这里进行善后处理

                        break;
                    }
                    System.out.println("Hi");
                }
            }
        };
        //开启线程
        thread.start();

        //中断线程
        Thread.sleep(3000); //睡眠 3 秒
        thread.interrupt();//中断 thread 线程
        System.out.println("开始中断线程");
    }

像这样做的优点有哪些呢?线程可以根据自己的逻辑来处理中断请求,比如结束循环、关闭资源或者忽略。

总结:先觉条件,调用interrupt();

  1. 如果线程因为调用 wait/join/sleep 等方法而阻塞挂起,则以InterruptedException异常的形式通知,重置中断标记。这时要不要结束线程取决于 catch 中代码的写法。可以选择忽略这个异常,也可以跳出循环结束线程。
  2. 如果没有 wait/join/sleep 等方法,
  3. Thread.interrupted() 判断当前线程的中断标志是否被设置,判断后,重置中断标志。
  4. Thread.currentThread().isInterrupted() 判断当前线程的中断标志是否被设置,不重置除中断标志。

3.6 等待线程 join()

有时,我们需要等待一个线程完成它的工作后,才能进行自己的下一步工作。

方法描述
join()等待该线程执行完成
join(long millis)最多等待指定的毫秒数,如果线程在该时间内没有执行完成,当前线程将继续执行
join(long millis, int nanos)最多等待指定的毫秒数和纳秒数,如果线程在该时间内没有执行完成,当前线程将继续执行
public class Main {
    public static void main(String[] args) {
        Thread thread = new Thread(){
            @Override
            public void run(){
                for (int i = 0; i < 9; i++) {
                    System.out.println("thread");
                }
            }
        };

        thread.start();//开启线程

        System.out.println("join()前");
        try {
            thread.join();//先等 thread 线程执行完
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("join()后");
    }
}

如果在join()之前thread线程已经执行完了的话,join()就不会阻塞了。

这些join()方法提供了线程之间的协同执行机制,允许一个线程等待另一个线程执行完成后再继续执行。这对于需要线程执行顺序或线程之间的依赖关系的场景非常有用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/679647.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Centos7安装和配置Mysql5.7

第一步&#xff1a;获取mysql YUM源 进入mysql官网获取RPM包下载地址&#xff0c;下面就是mysql5.7的Yum仓库的rpm包&#xff1a; mysql5.7链接地址&#xff1a; https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm 第二步&#xff1a;下载和安装mysql…

卷福的十年同学会

1.一通电话 某个上班日的午休时间里&#xff0c;小卷正趴在办公桌玩着手机准备睡一会&#xff0c;“叮咚”&#xff0c;一条微信消息弹出来&#xff0c;是大学的班群消息。 “五一期间大家来学校聚一下吧&#xff0c;今年是我们成为同学的十年了&#xff0c;大家提前报名哦&a…

Qt设置软件启动动画(支持图片和视频俩种方式)

目录 软件启动动画效果静态背景动态背景 程序启动动画QSplashScreen启动时加载静态图片启动时加载视频动画将启动动画置于所有窗口顶层 软件启动动画效果 先来看效果。下面录制了加载图片和gif动图的俩种效果。 静态背景 动态背景 这里我加载了一个gif的动图&#xff0c;你也…

AMBA AHB的burst termination

前言 在AMBA AHB协议中&#xff0c;AHB master可以用burst传输连续取多笔数据。AHB定义了4、8和16拍的burst传输、未定义长度的burst传输和单次传输。Burst传输中支持incrementing和wrapping。 Incrementing burst用于访问顺序的memory地址&#xff0c;burst中每个拍的地址都…

数据压缩的常用手段以及方法

0. 简介 之前我们在《经典文献阅读之–R-PCC(基于距离图像的点云压缩方法)》中提到了&#xff0c;我们可以通过一些算法层面来完成数据的压缩&#xff0c;而其实更简单或者说更直接的方法就是使用half这种形式来完成数据压缩。 1. half和float Half是用16位表示浮点数的一种…

什么是 FL Studio?2023年最新版 FL Studio21.0.3.3517中文版图文安装教程

什么是 FL Studio&#xff1f; FL Studio 是一个数字音频工作站 (DAW)。该软件借助各种编辑工具、插件和效果&#xff0c;让您可以录制、混音和掌握高度复杂的音乐作品。FL Studio 还允许您注册和编辑 MIDI 文件&#xff0c;您可以在众多可用乐器之一上演奏这些文件。FL Studi…

树莓派 python3.9降级为python3.7

今天烧录了一个官方烧录器中的最新的镜像&#xff0c;打开之后python的版本是3.9的&#xff0c;之前做的一些东西都是基于python3.7的&#xff0c;再重新架构十分麻烦&#xff0c;于是干脆就把python3.9进行降级&#xff0c;降为python3.7. 这个镜像不像之前的一些镜像&#x…

通用商城项目(上)

通用型产品&#xff08;电商&#xff09;发布解决方案落地实现&#xff08;基于分布式微服务技术栈&#xff1a; SpringBootSpring CloudSpring Cloud Alibaba VueElementUl MyBatis-Plus MySQL Git Maven Linux Nginx Docker 前后端分离&#xff09; 项目技术栈和前置技术 项…

【软件设计师暴击考点】操作系统知识高频考点暴击系列【一】

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;软件…

Web网页制作-知识点(1)——HTML5介绍、HTML5的DOCTYPE声明、HTML基本骨架、标题标签、段落 换行、水平线图片图片路径、超链接

目录 HTML5介绍 HTML5的DOCTYPE声明 HTML基本骨架 标题标签 段落、换行、水平线 图片 图片路径* 超链接 HTML5介绍 HTML5是用来描述网页的一种语言&#xff0c;被称为超文本标记语言。用HTML5编写的文件&#xff0c;后缀以.html结尾 HTML是一种标记语言&#xff0c;标…

自动化神器AutoIt,告别重复劳动

概要 计算机已经进入大众家庭多年&#xff0c;它给我们带来了便利&#xff0c;却也带来了枯燥、重复、机械的重复工作。今天&#xff0c;我要和大家分享一款自动化工具AutoIt&#xff0c;它能够帮助你告别这些烦恼&#xff0c;并提高工作效率。 AutoIt 是一款完全免费的Windows…

leetcode82. 删除排序链表中的重复元素 II(java)

删除排序链表中的重复元素 leetcode82. 删除排序链表中的重复元素 II题目描述一次遍历代码演示 链表专题 leetcode82. 删除排序链表中的重复元素 II 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/remove-duplicates-fr…

1.1 编写一个简单的C++程序

博主介绍&#xff1a;爱打游戏的计算机专业学生 博主主页&#xff1a;夏驰和徐策 所属专栏&#xff1a;夏驰和徐策带你从零开始学C 1.1.0 这段话告诉我们什么&#xff1f; 这段话解释了一个C程序中的main函数的基本结构和功能。 它告诉我们以下几点&#xff1a; 1. C程序的…

Debian11 编译bluez

之前的几篇文章写过如果编译x86和dv300 版本的bluez&#xff0c;不过那都是在 Centos7 上编译的。然而当我从taobao 上买了一个蓝牙适配器后发现无法使用&#xff08;淘宝客服说不支持Centos&#xff0c;只支持ubuntu 和 debian&#xff09;。再者 Centos 现在也停止支持服务了…

头歌网页设计与制作实训答案

我这里已经看不见原题目了&#xff0c;只粘贴了有Begin和End部分的代码&#xff0c;如果题目符合但答案不符合的的&#xff0c;欢迎在评论区找我。如果有帮助&#xff0c;请赞一个。注意看目录里有没有你需要的。 目录 一、HTML——基础 1.初识HTML: 简单的Hello World网页制…

程序员秋招最全Java面试题及答案整理(2023最新版)

前言 大家好&#xff0c;最近一个月&#xff0c;花了不少时间&#xff0c;给大家整理了一套 2023 的技术面试资料 包括各大厂最新面试题以及面经解析涉及JVM&#xff0c;Mysql&#xff0c;并发&#xff0c;Spring&#xff0c;Mybatis&#xff0c;Redis&#xff0c;RocketMQ&a…

Firefly-SRC资产探测平台

前言 Firefly是一个集资产管理、信息收集和漏洞扫描的综合平台。 Firefly-SRC依托于Firefly平台中的信息收集功能&#xff0c;不断收集和整理各大src相关资产数据。希望能为各位白帽子师傅们提供更稳定可靠的src资产数据&#xff0c;减少师傅挖洞前期的信息收集时间&#xff0c…

一体化个人门户Web Portal

什么是 Web Portal ? Web Portal 是一个一体化的 Web 仪表板&#xff0c;提供许多小部件来构建个人门户。具有加载外部插件的能力。对于那些只需要链接仪表板并希望使用 yaml 配置它的人来说&#xff0c;Lite 版是一个精简版本。 构建镜像 如果你不想自己构建&#xff0c;可以…

Qt的基本知识与应用

一、C梳理 1. 面向对象的三大特性 1.1 封装 把类的一些属性和细节隐藏&#xff08;private、protected&#xff09;&#xff0c;根据读写需要重新开放外部调用接口&#xff08;public、protected&#xff09;。 1.2 继承 在已有的类的基础上创建一个新的类&#xff0c;新的类拥…

最新AI创作系统V5.0.2+支持GPT4+支持ai绘画+实时语音识别输入+文章资讯发布功能+用户会员套餐

最新AI创作系统V5.0.2支持GPT4支持ai绘画实时语音识别输入文章资讯发布功能用户会员套餐&#xff01; AI创作系统一、源码系统介绍二、AI创作系统程序下载三、安装教程四、主要功能展示五、更新日志 AI创作系统 1、提问&#xff1a;程序已经支持GPT3.5、GPT4.0接口 2、支持三种…