【JavaEE】Java中的多线程 (Thread类)

news2024/11/24 18:34:55

作者主页:paper jie_博客

本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。

本文录入于《JavaEE》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造,将MySQL基础知识一网打尽,希望可以帮到读者们哦。

其他专栏:《MySQL》《C语言》《javaSE》《数据结构》等

内容分享:本期会对JavaEE中一个关于多线程的重要类Thread进行分享~

目录

什么是Thread

创建线程

继承Thread类

实现Runnable接口

匿名内部类创建Thread子类对象

匿名内部类创建Runnable子类对象

lambda表达式创建子类对象

Thread类的方法与常见属性

构造方法

常见属性

常用方法

启动线程 - start()

中断线程 

引入标记

interrupt()

异常的原因

等待程序 - join()

获取当前线程引用 - currentThread()


什么是Thread

Thread类是在Java标准库中的,它可以视为是对操作系统提供的API进一步的抽象与封装. 一个Thread实例对象我们可以认为是一个线程.

创建线程

继承Thread类

这里需要继Thread类来创建一个线程类. 因为这里要重写run方法.里面就是这个线程需要执行的逻辑.

然后还需要创建它的实例,这样一个线程才算创建出来了. 最后需要调用start方法启动线程.

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("hello Thread");

    }
}
public class ThreadDemo1 {
    public static void main(String[] args) {
        Thread t = new MyThread();
        t.start();
        System.out.println("hello main");
         
    }
}

实现Runnable接口

创建Thread实例,调用Thread构造方法时将Runnable对象作为参数.

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("线程运行代码");
    }
}
public class ThreadDemo2 {
    public static void main(String[] args) {
        Thread t = new Thread(new MyRunnable());
        t.start();
        System.out.println("hell main");

    }
}

匿名内部类创建Thread子类对象

这里后面是Thread类的匿名子类.

public class ThreadDemo3 {
    public static void main(String[] args) {
        Thread t = new Thread("这是我"){
            @Override
            public void run() {
                System.out.println("这是匿名方法");
                while(true) {
                    System.out.println("heeh");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        };
        t.start();
    }
}

匿名内部类创建Runnable子类对象

public class ThreadDemo4 {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable(){
            @Override
            public void run() {
                System.out.println("匿名创建Runnable子类");
            }
        });
        t.start();
    }
}

lambda表达式创建子类对象

public class ThreadDemo5 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            System.out.println("lambda表达式创建子类对象");
        });
        t.start();
    }
}

Thread类的方法与常见属性

构造方法

这里第三个和第四个可以重命名,这样可以更好的进行调试.

常见属性

ID是这个线程的唯一表示,不同的线程ID是不会重复的

名称一般就是调试的时候可以用到

状态表示一个线程当前所处的情况.一般有就绪状态和堵塞状态

优先级表示线程是不是更容易被调度

前台线程的运行会阻止进程的结束,后台线程的运行不会阻止进程的结束.一个进程的结束需要等所有前台线程执行完才会结束,不然就算是main线程执行完了也不会结束.我们创建的线程默认都是前台线程.

是否存活简单来说就是run方法是否执行完了. Java中Thread实例虽然代表的是多线程,但是它的生命周期和内核中创建出来的线程PCB的生命周期不是一样的.

此时虽然Thread实例对象有了,但是内核中线程PCB还没创建,isAlive是false.只有在t.start()执行后内核中的PCB才会创建出来,这时isAlive为true

当run方法执行完后,内核中的PCB就销毁了,这时isAlive为false.

常用方法

启动线程 - start()

这里Thread实例对象虽然创建出来了,但是线程并未真正的启动.调用start()后才算真正的创建出了一个线程. 这里的start()才是在内核中创建出一个线程. 调用start()创建线程本质上就是调用系统的API来创建线程.

这里一个线程只能调用一次start(),再次使用start需要用另一个线程对象来调用.不然它会报出一个非法线程状态的异常.

public class ThreadDemo1 {
    public static void main(String[] args) {
        Thread thread = new Thread() {
            @Override
            public void run() {
                System.out.println("线程");
            }
        };
        thread.start();
        thread.start();
        System.out.println("hell main");
    }
}

中断线程 

中断一个线程就是提前让这个线程的run方法结束.常用的方法有两种:

1. 通过引入一个标记

2. 通过interrupt()方法

引入标记

这里通过flag这个标记来让run方法提前结束.当main线程执行到flag = true时,另一线程就会提前结束.

public class ThreadDemo2 {
    public static  boolean flag = false;
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while(!flag) {
                    System.out.println("hell Thread");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        });
        thread.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("终止这个线程");
        flag = true;
    }
}

这里注意,flag标识是不能在main方法内中,不能作为局部变量.虽然lambda匿名内部类可以通过变量捕捉访问到外面的局部变量.但是这个局部变量必须是不可变的,是final修饰的,这就和我们需要通过改变标记来终止线程发生冲突了,这就不可行.

必须是final是因为main方法和Thread都有自己的函数栈帧.他们生命周期不同.flag是在属于main的栈帧中,一但main执行完了,它的栈帧就会销毁,Thread再想使用就用不到了. 这里变量捕捉就是为了这个而诞生.它就是传参,本质上就是在需要的线程上将flag拷贝一份.为了保证flag的一致性就让它不能改变.

interrupt()

Thread里面自带一个标志位.我们可以通过方法来获取和改变这个标志位.

这里可以用Thread.interrupted()或者Thread.currentThread().isInterrupted()来获取内置的标志位.

interrupt()方法可以改变标志位.

这里使用了Thread.currentThread().isterrupted:

public class ThreadDemo3 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while(!Thread.currentThread().isInterrupted()) {
                System.out.println("hell Thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("中断它");
        thread.interrupt();

    }
}

但运行代码后我们会发现问题:

这里会发现它会抛出一个中断异常,然后继续运行,并没有停下来.

异常的原因

这时因为这里interrupt()方法提前唤醒了sleep,这个时候sleep就会做两件事:

1. 抛出InterruptedExecption这个异常

2. 将内置标志位还原.

所有这会导致线程继续运行.

需要线程停下来,处理方法我们在catch里面加上break就可以了.

这里在catch中我们有三种处理方法:

1. 让线程立刻停下来

2. 让线程先运行一些代码再停下来

3. 让线程不停下来继续运行

 我们处理异常也有几种常见的方法:

等待程序 - join()

join方法可以调整线程执行的先后顺序.虽然说线程的调度执行是随机调度的.但这里join可以将线程进行堵塞从而影响到了线程的执行先后顺序.join所在的线程会发生堵塞,在调用join方法线程运行完后,这个线程的堵塞状态才会解除.

注意: 这里是调用join()的线程被等待先执行,join()所在的线程等待,后执行.

join()方法有三种:

第一种: 死等,需要等等待的线程执行完才会解除堵塞状态

第二种: 有时间的等待, 在一定时间内进行堵塞.超出时间范围就会解除堵塞状态

第三种:精确到微秒的有时间等待.

一般情况下,我们最常用的就是第二种情况:

public class ThreadDemo4 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while(true) {
                System.out.println("hell main");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        thread.start();
        thread.join();
        while(true) {
            System.out.println("hell ");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

        }
    }
}

这段代码,就是main线程进入堵塞状态,等待Thread线程结束. 虽然说Thread这个线程这执行中可以和其他多个线程共同进行调度执行,但由于main线程一直在等待,就算Thread线程在CPU上进行了多次切换也不影响这个线程先执行完.

这里注意: 我们的interrupt方法可以将join线程提前唤醒.

获取当前线程引用 - currentThread()

 在使用类继承Thread创建线程方法我们可以用this直接引用这个对象.但是当使用lambda/匿名内部类/Runnable时this就不再指向Thread对象了.这时我们获取Thread对象引用就需要使用currentThread()方法了. 

public class ThreadDemo7 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            System.out.println("hello Thread");
            System.out.println(Thread.currentThread().getName());
        });
        t.start();
    }
}

休眠当前线程 - sleep() 

sleep可以将当前线程休眠一定时间,这个时间可以自己设定.但使用它需要抛出异常或者try- catch.这里休眠的时间因为线程调度的不可控,一般都会大于等于设定的时间.

它也有两种方法:

一般都是使用第一种,第二种是精确到微秒.

public class ThreadDemo8 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            try {
                Thread.sleep(1111);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("休眠1.111秒");
        });
        t.start();
    }
}

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

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

相关文章

c语言,输入整数n(行数,本例为4),按照如下规则打印数字图片 1 5 9 13 2 6 10 14 3 7 11 15 4 8 12 16

c语言&#xff0c;输入整数n(行数&#xff0c;本例为4&#xff09;&#xff0c;按照如下规则打印数字图片 1 5 9 13 2 6 10 14 3 7 11 15 4 8 12 16 以下是使用C语言编写的程序&#xff0c;根据输入的行数打印数字图片的规则&#xff1a; #include <stdio.h>int main() …

深度学习大数据物流平台 python 计算机竞赛

文章目录 0 前言1 课题背景2 物流大数据平台的架构与设计3 智能车货匹配推荐算法的实现**1\. 问题陈述****2\. 算法模型**3\. 模型构建总览 **4 司机标签体系的搭建及算法****1\. 冷启动**2\. LSTM多标签模型算法 5 货运价格预测6 总结7 部分核心代码8 最后 0 前言 &#x1f5…

Spinnaker 基于 docker registry 触发部署

docker registry 触发部署 Spinnaker可以通过Docker镜像的变化来触发部署&#xff0c;这种方法允许你在Docker镜像发生变化时自动启动新的部署流程。 示例原理如下图所示&#xff1a; 以下是如何在Spinnaker中实现基于Docker Registry触发部署的配置流程。最终实现的效果如下…

3D ACIS Modeler和HOOPS Visualize助力鲁班软件打造BIM数字化平台

鲁班软件成立于2001年&#xff0c;始终致力于BIM技术研发和推广&#xff0c;为建筑产业相关企业提供基于BIM技术的数字解决方案&#xff0c;专注打造能够支撑建筑企业集团发展的BIM数字化平台鲁班工程管理数字平台(Luban Builder)&#xff0c;以及可承载园区级或城市级的BIM、C…

NX二次开发UF_CURVE_create_arc_3tangent 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CURVE_create_arc_3tangent Defined in: uf_curve.h int UF_CURVE_create_arc_3tangent(tag_t tangent_object1, tag_t tangent_object2, tag_t tangent_object3, UF_CURVE_help_…

Sass基础知识详细讲解【附带表图】

文章目录 前言使用 SassRack / Rails / Merb插件缓存选项语法选择编码 Sass CSS扩展Sass 注释输出 Sass 脚本Sass -规则和指令Sass 控制指令和表达式 Sass 混入指令Sass 功能指令命名约定Sass 输出样式:nested:expanded:compact:compressedSass 扩展缓存存储自定义导入 后言 前…

算法-技巧-中等-寻找重复数,环形链表|,||

记录一下算法题的学习13 这次代码中运用到的技巧是「Floyd 判圈算法」&#xff08;又称龟兔赛跑算法&#xff09;&#xff0c;它是一个检测链表是否有环的算法 我们想象乌龟tortoise和兔子rabbit在链表上移动&#xff0c;乌龟爬的慢&#xff0c;兔子爬的快&#xff0c;当乌龟和…

芯片技术前沿:了解构现代集成电路的设计与制造

芯片技术前沿:解构现代集成电路的设计与制造 摘要:本文将深入探讨芯片技术的最新进展,重点关注集成电路的设计与制造。我们将带领读者了解芯片设计的基本流程,包括电路分析、版图设计和验证等步骤,并介绍当前主流的制造工艺。此外,我们还将讨论芯片行业面临的挑战以及未…

【腾讯云云上实验室】探索向量数据库背后的安全监控机制

当今数字化时代&#xff0c;数据安全成为了企业和个人最为关注的重要议题之一。随着数据规模的不断增长和数据应用的广泛普及&#xff0c;如何保护数据的安全性和隐私性成为了迫切的需求。 今天&#xff0c;我将带领大家一起探索腾讯云云上实验室所推出的向量数据库&#xff0c…

大电流和大电压谁对人体伤害大

突然想起以前看的这个&#xff0c; 网上有很多解答了这个问题&#xff0c;答案是大电流比大电压对人体伤害大。 我之所以重新来写些&#xff0c; 是想起一种有趣的比喻&#xff0c; 这个答案不绝对。 先看一个场景&#xff0c; 一群牛和一头老虎对你冲来&#xff0c; 谁对你的…

计算机毕业设计|基于SpringBoot+MyBatis框架的电脑商城的设计与实现(用户上传头像+用户收货管理)

计算机毕业设计|基于SpringBootMyBatis框架的电脑商城的设计与实现&#xff08;用户上传头像&#xff09; 该项目分析着重于设计和实现基于SpringBootMyBatis框架的电脑商城。首先&#xff0c;通过深入分析项目所需数据&#xff0c;包括用户、商品、商品类别、收藏、订单、购物…

每日汇评:黄金有望在美欧通货数据周回升至2020美元上方

金价在2000美元以上占据主导地位&#xff0c;巩固了其2018美元的六个月高点&#xff1b; 美元在避险情绪中暂停下跌&#xff0c;美债收益率小幅上升&#xff1b; 金价本周收于2000美元以上&#xff0c;在关键通胀数据公布之前将有更多涨幅&#xff1b; 黄金价格已经从周一亚洲早…

SOLIDWORKS髙级孔命令及相关问题

本文介绍的是SOLIDWORKS髙级孔的命令应用。髙级孔主要用来做一些模型上的组合孔特征。我们先来看一个典型的例子&#xff0c;如图1所示&#xff0c;将轴侧视图能看到的3个面先进行“更改透明度”操作&#xff0c;以便看到模型内部孔的特征。 添加图片注释&#xff0c;不超过 14…

配电房无人值守监控系统

配电房无人值守监控系统是一种特殊的智能化监控系统&#xff0c;专为无人值守的配电房设计。依托电易云-智慧电力物联网&#xff0c;它采用先进的技术手段&#xff0c;实现对配电房环境、设备等的全方位实时监测和自动控制&#xff0c;确保配电房在无人员在场的情况下仍能安全、…

小波降噪的原理,以及软阈值函数和硬阈值函数的详细定义,应用和区别,以及数学公式的解释!!!看完你就懂了软阈值函数和硬阈值函数

文章目录 前言一、软阈值函数和硬阈值函数是什么&#xff1f;二、软阈值函数和硬阈值函数的区别三、软阈值函数和硬阈值函数的应用四、软阈值函数和硬阈值函数的数学公式总结 前言 小波降噪是一种应用小波理论的信号降噪方法&#xff0c;主要通过减少噪声的干扰&#xff0c;同…

Intellij Idea 断点小圆变成灰色怎么处理

场景1&#xff1a;变成了灰色实心圆 原因 断点变成灰色通常表示该断点处于失效状态。这可能是由于无意中点击了debug调试下方的“mute breakpoints”按钮导致的。 解决方案 依次点击设置小图标->View Options->Mute BreakPoints. 点击后 Mute BrakPoints左侧显示✔ 符号…

亥姆霍兹线圈的组成

亥姆霍兹线圈是由两个半径、匝数、电流★全相同的线圈&#xff0c;距离为半径长度&#xff0c;运行电流方向相同组成。 亥姆霍兹线圈是一种产生均匀磁场的线圈&#xff0c;其磁场特点是在内部产生均匀度较高的磁场&#xff0c;一般长螺线管的均匀度要优于赫姆霍兹线圈&#xf…

2020年06月 Scratch(四级)真题解析#中国电子学会#全国青少年软件编程等级考试

Scratch等级考试(1~4级)全部真题・点这里 一、单选题(共15题,每题2分,共30分) 第1题 执行下图程序后,“花名”列表的第3项是? A:莲花 B:丁香 C:合欢 D:月季 答案:C 列表基本知识,选C。 第2题 执行如下图所示程序后,其结果为? A: B:

Linux(CentOS7.5):新增硬盘分区纪实

一、服务器概述 1、既有一块系统硬盘&#xff0c;新增一块100G硬盘。 2、要求&#xff0c;将新插入硬盘分为&#xff1a;20G、30G、50G。 二、操作步骤 1、确认新硬盘是否插入成功&#xff1a; fdisk -l# 红色框出来的&#xff0c;为识别出来的新硬盘信息 # 黄色框出来的&#…

C语言——输入 10 个数,分别统计其中正数、负数、零的个数

#include <stdio.h> int main() {int numbers[10]; // 存储输入的10个数int positive_count 0; // 正数计数器int negative_count 0; // 负数计数器int zero_count 0; // 零计数器// 输入10个数printf("请输入10个数&#xff1a;\n");for (int i 0; i …