【JavaEE 初阶(一)】初识线程

❣博主主页: 33的博客❣
▶️文章专栏分类:JavaEE◀️
🚚我的代码仓库: 33的代码仓库🚚
🫵🫵🫵关注我带你了解更多线程知识

在这里插入图片描述

目录

  • 1.前言
  • 2.进程
  • 3.线程
  • 4.线程和进程的区别
  • 5.Thread创建线程
    • 5.1继承Thread创建线程
    • 5.2实现Runnable接口
    • 5.3lambda表达式
  • 6.Thread常见方法
    • 6.1Thread常见属性
    • 6.2 中段一个线程- interrupt()
    • 6.3等待线程-jion()
  • 7.线程的状态
    • 2.1代码实现
    • 2.2运行结果

1.前言

我们设想:一家公司要去银行办理业务,既要进行财务转账,又要进行福利发放,还得进行缴社保。如果只有张三一个会计就会忙不过来,耗费的时间特别长。为了让业务更快的办理好,张三又找来两位同事李四、王五一起来帮助他,三个人分别负责一个事情,分别申请一个号码进行排队,自此就有了三个执行流共同完成任务,但本质上他们都是为了办理一家公司的业务。此时,我们就把这种情况称为多线程,那么在Java中该如何实现多线程呢?我们一起来学习吧!!


2.进程

提到线程,我们就不得不先了解进程了,那么什么是进程呢?进程就是运行起来的一个个程序。 引入进程有什么作用呢?是为了实现并发编程。但进程有很多,系统是如何管理它们的呢?那就是"先描述,再组织"

描述:使用PCB结构表示进程的各种属性。
PCB中的重要特性: 1.pid(进程标识符)2.内存指针(表示进程持有的内存资源,比如内存空间具体在哪里,有哪些部分组成,每个部分干啥的等等)3.文件描述表(表示进程持有的硬盘资源,类似于顺序表)4.CPU资源(状态、优先级、上下文、记账消息,这些都主要来完成进程调度)

组织:利用双显链表,把PCB的这些结构串起来。
进程是资源分配的基本单元,创建进程需要给他分配内存和硬盘资源需要消耗的时间太多,销毁一个进程销毁的时间很多,调度一个进程消耗的时间也很多,如果频繁的创建或者销毁一个资源,这个时候的开销就是非常大的,为了解决这个问题,我们引入了线程(Thread)。


3.线程

线程也叫做“轻量级进程”,创建线程,销毁线程,调度线程都比进程更快。但线程不能独立存在,要依附于进程,即一个进程至少包含一个线程!但每一个线程都是独立执行的,一个进程,最开始的时候必须要包含一个线程,这个线程负责完成执行代码的工作,也可以创建出多个线程,完成并发执行的效果。

线程的特点
1.每一个线程都可以独立的去cpu上执行
2.同一个进程的多个线程之间公用一份内存空间和文件资源
3.同一个进程中,采用多线程的方式能提高效率,但有一定限度,如果无限度的引入线程可能是调度开销增大,导致效率反而降低
4.同一个进程中,一个线程抛出异常,如果没有妥善处理可能会导致整个进程崩溃。


4.线程和进程的区别

1.一个进程包含一个或多个线程
2.进程和线程都是用来实现并发编程的,但线程比进程更轻量,更高效
3.进程和进程之间具有独立性,如果一个进程异常不会影响到其他进程,但线程和线程之间可能会相互影响
4.进程是资源分配的基本单位,线程是调度执行的基本单位


5.Thread创建线程

线程是操作系统的概念,操作系统提供了一些API可以操作线程,Java对系统API进行了封装,使用Thread类就可以创建出一个线程.

5.1继承Thread创建线程

方法1:

package Thread;
class MyThread extends Thread{
    @Override
    //线程的入口
    public void run() {
        while (true) {
            System.out.println("hello thread");
			//隔1s轮转
            try {
                Thread.sleep(1000);//1s
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class Demo1 {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new MyThread();
        //start和run都是Thread的成员
        //run只是描述线程的入口,线程主要做什么
        //start则是真正的调用了系统API创建了线程,让线程再调用run()
        t.start();
        while (true){
            System.out.println("hello main");
            Thread.sleep(1000);
        }

    }
}

方法2:匿名内部类

package thread;
public class Demo3 {
    public static void main(String[] args) {
        Thread t = new Thread() {
        //匿名内部类
            @Override
            public void run() {
                while (true) {
                    System.out.println("hello thread");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        t.start();
        while (true) {
            System.out.println("hello main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

注意
1.Thread在java.lang这个包下并不用导包
2.start方法内部会调用系统的API生成一个线程再调用run函数,和run函数的效果类似,但本质区别为:是否会创建一个线程


5.2实现Runnable接口

方法1:

package thread;
class MyRunnable implements Runnable {
    @Override
    public void run() {
        while (true) {
            System.out.println("hello thread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class Demo2 {
    public static void main(String[] args) {
        Runnable runnable = new MyRunnable();
        Thread t = new Thread(runnable);
        t.start();
        while (true) {
            System.out.println("hello main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

方法2:匿名内部类

package thread;
public class Demo4 {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    System.out.println("hello thread");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        t.start();
        while (true) {
            System.out.println("hello main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

5.3lambda表达式

package thread;
public class Demo6 {
    public static void main(String[] args) {
     //lambda表达式
        Thread t = new Thread(() -> {
            while (true) {
                System.out.println("hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"第一个线程");
       t.start();
       while (true) {
            System.out.println("hello main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

6.Thread常见方法

6.1Thread常见属性

属性获取方法
IDgetId
名称getName
状态getState
优先级getPriority
是否后台线程isDaemon
是否存活isAlive
是否被中断isInterrupted

ID 是线程的唯一标识,不同线程不会重复
名称是各种调试工具用到
状态表示线程当前所处的一个情况,下面我们会进一步说明
优先级高的线程理论上来说更容易被调度到
后台线程:守护线程,后台线程结束与否不影响整个程序,但如果前台线程没有结束,进程也不会结束。
是否存活:判断内核线程是否已经销毁

6.2 中段一个线程- interrupt()

首先我们要知道,一个线程如果时间特别长,那么大概率在线程的内部有循环再一直执行。如果想要中断此线程,那么我们就想办法尽快让run函数执行完成,那么怎么能让循环快速执行完呢?其实我们只需要在循环处添加一个条件,条件不成立就结束了。
例如:

public class Demo7 {
    public static boolean  flag=false;
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(()->{
            while (!flag){
                System.out.println("t进程");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("工作完毕");
        });
        t.start();
        Thread.sleep(5000);
        flag=true;
        System.out.println("打断进程");
    }
}

注意
定义flag的时候只能定义为成员变量,不能定义为局部变量,因为在lambda有一个语法规则:变量捕获。把当前作用域的变量在lambda中复制了一份,在变量捕获时有一个前提限制:必须只能捕获final修饰的变量或者变量不能做任何修改。如果把flag设置为成员变量,就不再是变量捕获的与法律,而是内部类访问外部类的属性。

但是如果我们每次都专门定义一个标志位来打断线程是非常麻烦的,而且当处于睡眠模式下还不能立即就想应,在Thread类中有有一个标志位isInterupted来判定线程是否被打断。

public class Demo8 {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(()->{
            while (!Thread.currentThread().isInterrupted()){
                System.out.println("t进程");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    //唤醒sleep有3种操作
                    //1.不管它,继续执行t线程
                    //2.立即执行打断
                    break;
                    //3.进行一些其他操作
                }
            }
        });
        t.start();
        System.out.println("main进程");
        Thread.sleep(5000);
        System.out.println("t进程打断");
        t.interrupt();//打断
    }
}

说明
1.Thread.currentThread()表示当前线程即t线程
2.在正常情况下,sleep休眠时间完成才会被唤醒,如果调用interrupt()那么就提提前唤醒它触发InterruptedException异常
观察下图:虽然打断了t线程并且触发了InterruptedException异常,但t线程依然在执行。
在这里插入图片描述
出现上述情况是因为:interr唤醒sleep之后会抛出异常当同时也会清除标志位,这就使打断效果像没有生效一样。Java期望当线程收到“要中断”的信号使,由本身来决定接下来该怎么做。

6.3等待线程-jion()

等待一个线程即使指,当一个线程执行完毕时才能执行另外一个线程。

public class Demo9 {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(()->{
            for (int i=0;i<5;i++){
                System.out.println("t线程正在执行");
            }
        });
        t.start();
        //等待t线程执行结束再执行main线程
        t.join();
        System.out.println("t线程执行结束");
        System.out.println("main线程");

    }
}

7.线程的状态

在进程中最核心的状态就是就绪和阻塞状态,在线程中同样适用,同时java又赋予了线程一些其他的状态:

NEW:创建Thread对象安排了工作,但没有启动。
RUNNABLE:指就绪状态,即线程正在执行或者线程等待执行
TERMINATED: 工作完成了
TIMWD_WAITING:阻塞,由于sleep这种固定的时间方式而阻塞
WAITING: 阻塞,由于wat这种不固定的时间方式而阻塞
BLOCKED: 阻塞,由于锁竞争导致的阻塞
在Java中可以通过getState()方法来查看此时线程的状态。

2.1代码实现

public class Demo10 {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(()->{
            for (int i=0;i<3;i++){
                System.out.println("t线程在执行");
            }
        });
        System.out.println(t.getState());
        t.start();
        System.out.println(t.getState());
       Thread.sleep(3000);
        System.out.println(t.getState());
    }
}

2.2运行结果

在这里插入图片描述

总结:本篇文章主要介绍了线程的概念,为什么要引入线程,要理解线程和进程的区别,创建线程的几种方法,会运用Thread的一些常见方法。

下期预告:线程安全问题

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

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

相关文章

非平衡数据处理-SMOTE Tomek算法(互联网最全)

作者Toby&#xff0c;来源公众号&#xff1a;Python风控模型&#xff0c;非平衡数据处理-SMOTE Tomek算法 之前Toby老师讲了非平衡数据处理相关知识&#xff0c;具体内容和链接如下。 imbalanced data机器学习非平衡数据处理 Python非平衡数据处理_SMOTE-ENN 方法 非平衡数…

【SSM进阶学习系列丨分页篇】PageHelper 分页插件导入集成实践

文章目录 一、说明什么是分页PageHelper介绍 二、导入依赖三、集成Spring框架中四、编写Service五、编写Controller六、编写queryAllByPage页面展示数据 一、说明 什么是分页 ​ 针对分页&#xff0c;使用的是PageHelper分页插件&#xff0c;版本使用的是5.1.8 。 ​ 参考文档…

虚拟机网络实现桥接模式

虚拟机网络实现桥接模式 虚拟化软件&#xff1a;VMware 17 Linux&#xff1a;rocky8_9 主机&#xff1a;Win10 文章目录 虚拟机网络实现桥接模式1. 桥接模式介绍2. 查看Win本机的网络信息&#xff08;以笔记本电脑以WiFi联网为例&#x…

【Canvas与艺术】录王昌龄出塞诗“秦时明月汉时关”

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>使用HTML5/Canvas绘制秦时明月汉时关</title><style type&q…

【论文阅读】Sparse is Enough in Scaling Transformers

Sparse is Enough in Scaling Transformers 论文地址摘要1 介绍2 相关工作模型压缩。模型修剪模型蒸馏。稀疏注意力。张量分解。稀疏前馈。 3 Sparse is Enough3.1 稀疏前馈层3.2 稀疏 QKV 层3.3 稀疏损失层。 4 长序列的稀疏性4.1 长序列架构4.2 内存效率的可逆性4.3 泛化的循…

# 从浅入深 学习 SpringCloud 微服务架构(七)Hystrix(4)

从浅入深 学习 SpringCloud 微服务架构&#xff08;七&#xff09;Hystrix&#xff08;4&#xff09; 一、hystrix&#xff1a;使用 turbine 聚合所有的 hytrix 的监控数据测试。创建父工程 spring_cloud_hystrix_demo&#xff0c;导入相关依赖坐标。并在父工程 spring_cloud_…

C++校招八股

c类的访问权限与继承方式 公有成员在任何地方都可以被访问&#xff0c;包括类的外部和派生类。受保护成员在类的内部和派生类中可以被访问&#xff0c;但在类的外部不可访问。 私有成员只能在类的内部访问&#xff0c;包括类的成员函数和友元函数&#xff0c;不允许在类的外部…

MySQL45讲(一)(45)

如果使用的是unsigned int 做的主键&#xff0c;如果你用完了&#xff0c;在insert直接就是报冲突的错误 碰到这种情况&#xff0c;只能进行修改字段的属性了&#xff0c;把他换成big unsigned 了&#xff0c;所以建表对字段定义的时候就需要判断好&#xff0c;是否会超过 对于…

我的创作纪念日—128天的坚持|分享|成长

☘️博主介绍☘️&#xff1a; ✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ ✌✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux&#xff0c;也在扩展大数据方向的知识面✌✌️ ❣️❣️❣️大佬们都喜欢静静的看文章&am…

H3C MSTP 实验

H3C MSTP 实验 实验拓扑 ​​ 实验需求 所有交换机上创建 Vlan10&#xff0c;Vlan20&#xff0c;Vlan30 和 Vlan40所有交换机之间的端口配置为 Trunk&#xff0c;并放行相关 VLAN按照图示分区域配置 MSTP&#xff0c;并配置主备根网桥 实验步骤 VLAN基础配置&#xff08;…

RateLimiter 限流 —— 通过切面对单个用户进行限流和黑名单处理

关于登录的安全性管理有较多的手段&#xff0c;包括&#xff1b;设备信息、IP信息、绑定的信息、验证码登各类方式。不过在一些网页版的登录中&#xff0c;如果有人想办法把你的验证码给我&#xff0c;我就可以登录你的账户&#xff0c;查看你的数据。对于一些不法分子通过让你…

windows 驱动开发-DMA技术(二)

前面描述了DMA技术中适配器相关的部分以及DMA的分类&#xff0c;接下来看一下系统具体在支持两种DMA时候的操作的细微差别。 此处解释一下Scatter/Gather&#xff0c;这个也翻译为散点/收集&#xff0c;是指指示设备能够读取或写入内存中的任何区域&#xff0c;而不仅仅是特定…

构建智能化商旅服务:酒店中台云服务架构设计与实践

随着商旅行业的不断发展和智能化趋势的兴起&#xff0c;酒店中台云服务成为了提升服务质量和效率的关键。本文将探讨酒店商旅中台云服务的架构设计与实现&#xff0c;介绍其关键特点和最佳实践&#xff0c;助力商旅行业迈向智能化未来。 1. **需求分析与场景设计&#xff1a;*…

【阿里云服务器】ubuntu 22.04.1安装docker以及部署java环境

我的服务器配置是2GB CPU 2GB 内存 Ubuntu22.04 目录 一、阿里云 ubuntu 22.04.1安装docker 二、docker基础命令 三、Windows电脑访问云服务器 四、安装java环境 安装OpenJDK 8&#xff08;可以根据需要安装其他版本的JDK&#xff09; 安装java的依赖管理工具maven 一、…

基于yolov2深度学习网络模型的鱼眼镜头中人员检测算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 load yolov2.mat% 加载训练好的目标检测器 img_size [448,448]; imgPath test/; % 图像…

LeetCode 15 —— 三数之和

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 首先我们对数组进行从小到大排序&#xff0c;然后遍历数组 [ 0 , n u m s . s i z e ( ) − 3 ] [0,nums.size()-3] [0,nums.size()−3] 作为三元组中的 a a a&#xff0c;由于三元组的索引互不相同&#xff0c…

文件与IO基础常识知识

在这里&#xff0c;只介绍理论知识&#xff0c;不介绍代码。 目录 1.IO 1.1.字面概念 1.2.输入输出模型 2.文件 2.1.文件目录 2.2.文件路径 2.3.文件分类 1.IO 为了我们接下来学习的文件IO&#xff0c;所以我们先来认识什么是IO。 1.1.字面概念 &#xff08;1&#x…

【知识加油站】——机电产品数字孪生机理模型构建

明确一种多领域、多层次、参数化、一致性的机电一体化装备数字孪生机理模型构建准则&#xff01; 关键词英文简称&#xff1a; 数字孪生&#xff1a;DT物联网&#xff1a;IoT网络物理系统&#xff1a;CPS高级架构&#xff1a;HLA统一建模语言&#xff1a;UML数控机床&#xf…

Sarcasm detection论文解析 |A2Text-Net:一种用于讽刺检测的新型深度神经网络

论文地址 论文地址&#xff1a;A2Text-Net: A Novel Deep Neural Network for Sarcasm Detection | IEEE Conference Publication | IEEE Xplore github:lliyuan1117/A2Text-Net (github.com) 论文首页 A2Text-Net&#xff1a;一种用于讽刺检测的新型深度神经网络 &#x1f4c5…

Win11 怎么让软件运行后台全部显示在任务栏上 win11任务栏展开显示所有软件图标

Win11 怎么让软件运行后台全部显示在任务栏上 win11任务栏展开显示所有软件图标 方法二 搜索cmd 打开命令行面板 然后输入 explorer shell:::{05d7b0f4-2121-4eff-bf6b-ed3f69b894d9}就能显示出来了 ## 方法三 通知区域图标不存在 如图&#xff0c;显示为这样 这种时候桌面…