javaEE-多线程编程-3

目录

java 常见的包 :

回调函数:

什么是线程:

第一个线程:

验证多线程执行:

内核:

调用sleep()方法:

执行结果分析:

线程创建的几种方式:

1.继承Thread类,重写run()方法.

2.实现Runnable接口,重写run()方法.

3.继承Thread类,重写run()方法.但使用匿名内部类

4.实现Runnable接口,重写run()方法,但使用匿名内部类:

5.使用lambda表达式(推荐)

Thread的构造方法

Thread的常用的属性:

1.ID:jvm自动分配的身份标识,不同线程不会重复

2.名称是调试的时候用到的

3.状态:

4.优先级:

5.是否后台线程:

6.是否存活:


在写代码的时候,可以用多进程编程,也可以用多线程编程.

多进程编在java中不太推荐,因为与多进程编程相关的api,在java标准库中都没有提供.

系统提供了多线程编程的api,在java标准库中,把这些api都封装了,在代码中可以直接使用.

并且在面对频繁创建和销毁进程的时候,多线程编程具有非常大的优势.效率非常高.

java 常见的包 :

1. java.lang:系统常用基础类(String、Object),此包从JDK1.1后自动导入。

2. java.lang.reflect:java 反射编程包;

3. java.net:进行网络编程开发包。

4. java.sql:进行数据库开发的支持包。

5. java.util:是java提供的工具程序包。(集合类等) 非常重要

6. java.io:I/O编程开发包

Thread类就是java.long包下的类,不需要引入包就能直接使用.

一个.java文件中,只能有一个类被public修饰,若该类没有被public修饰,就只能在该包中,被别的类引用.

一个进程至少会有一个线程,该进程的第一个线程就是main线程,也就是主线程的入口方法.

回调函数:

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

简单来说:回调函数就是把一段代码,向传参一样,传递给其它代码,这段代码会在某个时刻被调用执行.这就叫做回调.

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。如果代码立即被执行就称为 同步回调,如果过后再执行,则称之为 异步回调。

什么是线程:

⼀个线程就是⼀个"执⾏流".每个线程之间都可以按照顺序执⾏⾃⼰的代码.多个线程之间"同时"执⾏ 着多份代码

第一个线程:

创建一个Thread01类,让该类继承Thread类,重写Thread类的run()方法,

在主函数中实例化该类,调用该类的start()方法,这样,不需要我们手动调用run()方法,待线程创建好后,会在合适的时机被jvm自动调用.(这种风格的函数,就被称为"回调函数"callback)

调⽤start()⽅法,才真的在操作系统的底层创建出⼀个线程.

package Thread_;

class MyThread01 extends Thread{
    @Override
    public void run() {//重写run()方法
        //run()方法就是该线程的入口
        while (true){
            System.out.println("Thread run");
        }
    }
}
public class Thread01 {
    public static void main(String[] args) {
        Thread thread01 = new MyThread01();
        thread01.start();//必须要调用start()方法,才能开启线程
        while(true){
        System.out.println("main ");
        }
    }
}

当引入多线程之后,代码中就可以同时具备多个执行流了.

验证多线程执行:

可以通过jdk/bin/jconsloe.exe文件看进程状态.

先运行自己写的代码,让后进行下面的操作

内核:

操作系统的内核是操作系统最核心的功能模块.(管理硬件,给软件提供稳定的运行环境)

简单来说:内核态是非常重要的,不允许用户修改的,划分出用户态和内核态也是目的是为了稳定,以防自己的应用程序把硬件设备或软件资源给搞坏了.

操作系统=内核+应用程序.

一旦开始执行,线程就会飞快的循环起来,使cpu占用率较高,进一步提高电脑的功耗,为了不让循环跑的那么快,可以在循环体中设置Thread类的sleep()方法,让每隔一定时间运行一次,这样就能降低电脑的功耗.

调用sleep()方法:

sleep()方法调用时,会有受查异常,需要手动抛出.

Mythread类中的run()方法内的异常抛出只能以try-catch的形式,不能以throws的形式,因为run()方法是重写父类的方法,父类没有throws这个异常,若加上throws,就修改了方法签名,因此,子类重写run()方法的时候,也就只能以try-catch的形式抛出异常了.

以try-catch的形式抛出异常:

以throws的形式抛出异常:

时间转换单位:

1s=1000ms(毫秒)

1ms=1000(微妙)

1um=1000nm(纳秒)

上面的第一个线程代码,可以看出,main()方法中有一个死循环,在Thread01类的run()方法中也有一个死循环,一般来说,一个代码中出现两个死循环,只会运行一个,但实际上这两个死循环中的代码都被运行了,这就说明是两个线程在同时执行.

执行结果分析:

从执行的结果上可以看出,thread和main是随机交替出现的,也就是说,每隔一秒钟,thread和main被执行一次,但是谁先被执行,是无法确定的.

每次最开始打印的结果,可以看到:都是main第一次被打印,这是因为在创建MyThrow01线程的时候,虽然该线程不是第一个线程,还是会有一定开销的,这个开销比创建进程要低很多(但也不是没有),就是这一点点的开销,使得main线程每次在最开始执行的时候强到了先机.

(注意:main线程是第一线程)

线程创建的几种方式:

1.继承Thread类,重写run()方法.

也就是上面的这种方式.

package Thread_;

class MyThread01 extends Thread{
    @Override
    public void run() {
        //run()方法就是该线程的入口
        while (true){
            System.out.println("Thread run");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
public class Thread01 {
    public static void main(String[] args) {
        Thread thread01 = new MyThread01();
        thread01.start();//必须要调用start()方法,才能开启线程
        while(true){
        System.out.println("main ");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

2.实现Runnable接口,重写run()方法.

Runnable接口需要搭配Thread类使用,才能真正在系统中创建出线程来
package Thread_;

class MyThread02 implements Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println("Thread01 run()");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
public class Thread02 {
    public static void main(String[] args) {
        MyThread02 runnable = new MyThread02();
        Thread thread1 = new Thread(runnable);//Runnable接口需要搭配Thread类使用,才能真正在系统中创建出线程来
        thread1.start();
        while(true){
            System.out.println("main()");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

    }
}

3.继承Thread类,重写run()方法.但使用匿名内部类

Thread t=new Thread(){//这里写的{}表示要定义一个类,并且这个新类继承Thread,
                        //且没有名字,用一次就不能再用了
                       //{}中可以定义新类的属性和方法
                        //此处的目的就是重写父类Thread的run()方法.
    @Override
    public void run() {
        while(true){
            System.out.println("Thread run03");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
};

这里的thread变量名指向的是新创建的Thread的匿名内部类(子类),而不是Thread类.

4.实现Runnable接口,重写run()方法,但使用匿名内部类:

Thread构造方法的参数,传了Runnable的匿名内部类的实例.

5.使用lambda表达式(推荐)

lambda表达式原理:

Thread thread=new Thread(()->{    //这里的()是形参列表,在这里,不需要传参数
                                 //()的前面应该有个函数名,这里是匿名的,所以没有名字
                                //->后面的{}是方法体,
    while(true){
        System.out.println("Thread run5");
        try{
        Thread.sleep(1000);
        }catch(InterruptedException o){
             throw new RuntimeException(e);
        }
    }
});

这里的规则是方法不能脱离类单独存在.

这几种方法都是等价的,作用都相同.

Thread的构造方法

1.构造方法:

前两个在前面创建线程的时候都提到了,

第三,四个:给线程起个名字:

在jcolsole.exe中就能看到线程名字被修改

自己创建的线程默认是按照Thread-0 1 2 ...创建的,线程之间的名字可以重复,起名字是为了方便调试.

Thread的常用的属性:

1.ID:jvm自动分配的身份标识,不同线程不会重复

2.名称是调试的时候用到的

3.状态:

线程有不同的状态:就绪状态,阻塞状态

4.优先级:

优先级⾼的线程理论上来说更容易被调度到,线程的优先级在java中,效果不是很明显

5.是否后台线程:

和后台线程相对应的是前台线程,当一个进程开始运行的时候,只有前台线程都运行结束,后台线程才会结束.

JVM会在⼀个进程的所有⾮后台线程结束后,才会结束运⾏。

目前代码创建的线程都是前台线程,都会阻止线程的结束,当全部都执行完了,才会结束整个进程.

设置线程为后台线程:在start之前setDaemon(true);此时,该线程就为后台线程

在start之前,给thread线程设置成了后台线程,在main函数之后,休眠2秒,thread线程就执行了2秒,打印了两遍,main线程结束了,thread线程为后台线程,也就结束了.

6.是否存活:

表示内核中的线程是否还存活,在start之前,还没有开始线程,isAlive为false,

只有调用了start,线程才开始执行,isAive才为true.

2s之后,run()已经结束,isAlive为false.

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

FFmpeg 框架简介和文件解复用

文章目录 ffmpeg框架简介libavformat库libavcodec库libavdevice库 复用(muxers)和解复用(demuxers)容器格式FLVScript Tag Data结构(脚本类型、帧类型)Audio Tag Data结构(音频Tag)V…

芯片级IO (Pad) Ring IP Checklist

SoC top顶层数字后端实现都会涉及到IO Ring (PAD Ring)的设计。这里面包括VDD IO,VDDIO IO, Signal IO, Corner IO,Filler IO,IO power cut cell等等。 数字后端零基础入门系列 | Innovus零基础LAB学习Day2 数字IC后端实现TOP F…

圣诞快乐(h5 css js(圣诞树))

一,整体设计思路 圣诞树h5(简易) 1.页面布局与样式: 页面使用了全屏的黑色背景,中央显示圣诞树,树形由三层绿色的三角形组成,每一层的大小逐渐变小。树干是一个棕色的矩形,位于三角…

Linux应用开发————mysql数据库表

mysql数据库表操作 查看表的结构 mysql> desc / describe 表名; 或者: mysql> show create table 表名; 常见数据库引擎: innodb, myISAM... 删除表 mysql> drop tabl…

移动网络(2,3,4,5G)设备TCP通讯调试方法

背景: 当设备是移动网络设备连接云平台的时候,如果服务器没有收到网络数据,移动物联设备发送不知道有没有有丢失数据的时候,需要一个抓取设备出来的数据和服务器下发的数据的方法。 1.服务器系统是很成熟的,一般是linu…

Unity中的委托和事件(UnityAction、UnityEvent)

委托和事件 🎒什么是委托,委托的关键字是Delegate,委托是一种函数的容器,运行将函数做为变量来进行传递 通过Delegate关键字我们声明了一个无参无返回的委托,通过这个委托我们可以存储无参无返回的函数 public deleg…

基于SpringBoot的“交流互动系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“交流互动系统”的设计与实现(源码数据库文档PPT) 开发语言:Java 数据库:MySQL 技术:SpringBoot 工具:IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能图 管理员登录界面图 个人信息界面图 个人…

LeetCode hot100-93

https://leetcode.cn/problems/longest-palindromic-substring/description/?envTypestudy-plan-v2&envIdtop-100-liked 5. 最长回文子串 给你一个字符串 s,找到 s 中最长的回文子串。状态定义 我们用一个二维数组 dp[i][j] 表示子串 s[i…j] 是否是回文&…

C语言入门指南:从零开始的编程之路

记得我刚开始接触编程时,也像很多初学者一样充满疑惑。编程看起来很神奇,但要如何开始呢?经过多年编程经验的积累,今天和大家分享如何入门C语言编程。 C语言诞生于1972年,由Dennis Ritchie在贝尔实验室开发。它的出现彻底改变了计算机编程的历史。虽然现在有很多更新的编程语…

详解Redis的String类型及相关命令

目录 SET GET MGET MSET SETNX SET和SETNX和SETXX对比 INCR INCRBY DECR DECRBY INCRBYFLOAT APPEND GETRANGE SETRANGE STRLEN 内部编码 SET 将 string 类型的 value 设置到 key 中。如果 key 之前存在,则覆盖,⽆论原来的数据类型是什么…

SpringBoot使用 AOP 实现自定义日志记录并保存在Mysql

本文主要介绍在 Spring Boot 中使用 AOP 实现自定义日志记录并保存在 Mysql 的方法。先阐述记录日志的重要性及传统方式的弊端,提出新方式,即通过创建自定义注解、切面类等,将重要日志存到数据库,还给出了创建日志表、注解类、切面…

对golang的io型进程进行off-cpu分析

背景: 对于不能占满所有cpu核数的进程,进行on-cpu的分析是没有意义的,因为可能程序大部分时间都处在阻塞状态。 实验例子程序: 以centos8和golang1.23.3为例,测试下面的程序: pprof_netio.go package m…

CTF入门:以Hackademic-RTB1靶场为例初识夺旗

一、网络扫描 靶机ip地址为192.168.12.24 使用nmap工具进行端口扫描 nmap -sT 192.168.12.24 二、信息收集 1、80端口探索 靶机开放了80和22端口,使用浏览器访问靶机的80端口,界面如下: 点击target发现有跳转,并且url发生相应变…

腾讯云智能结构化OCR:以多模态大模型技术为核心,推动跨行业高效精准的文档处理与数据提取新时代

🎼个人主页:【Y小夜】 😎作者简介:一位双非学校的大三学生,编程爱好者, 专注于基础和实战分享,欢迎私信咨询! 🎆入门专栏:🎇【MySQL&#xff0…

SD ComfyUI工作流 根据图像生成线稿草图

文章目录 线稿草图生成SD模型Node节点工作流程工作流下载效果展示线稿草图生成 该工作流的设计目标是将输入的图像转换为高质量的线稿风格输出。其主要流程基于 Stable Diffusion 技术,结合文本和图像条件,精确生成符合预期的线条艺术图像。工作流的核心是通过模型的条件设置…

Zabbix6.0升级为6.4

为了体验一些新的功能,比如 Webhook 和问题抑制等,升级个小版本。 一、环境信息 1. 版本要求 一定要事先查看官方文档,确认组件要求的版本,否则版本过高或者过低都会出现问题。 2. 升级前后信息 环境升级前升级后操作系统CentOS…

网络安全概论——身份认证

一、身份证明 身份证明可分为以下两大类 身份验证——“你是否是你所声称的你?”身份识别——“我是否知道你是谁?” 身份证明系统设计的三要素: 安全设备的系统强度用户的可接受性系统的成本 实现身份证明的基本途径 所知:个…

LabVIEW中的“Synchronize with Other Application Instances“

在LabVIEW中,“Synchronize with Other Application Instances”是一个常见的提示或错误,通常出现在尝试并行运行多个LabVIEW实例时,特别是当你打开多个VI或项目时。这个问题可能影响程序的执行流程,导致不同实例之间的数据同步或…

OpenGL ES 01 渲染一个四边形

项目架构 着色器封装 vertex #version 300 es // 接收顶点数据 layout (location 0) in vec3 aPos; // 位置变量的属性位置值为0 layout (location 1) in vec4 aColors; // 位置变量的属性位置值为1 out vec4 vertexColor; // 为片段着色器指定一个颜色输出void main() {gl…

Maven 生命周期

文章目录 Maven 生命周期- Clean 生命周期- Build 生命周期- Site 生命周期 Maven 生命周期 Maven 有以下三个标准的生命周期: Clean 生命周期: clean:删除目标目录中的编译输出文件。这通常是在构建之前执行的,以确保项目从一个…