java中多线程

文章目录

  • 多线程
    • 进程和线程
      • 进程
      • 线程
    • 继承Thread类方式实现多线程
    • 设置线程名字的两个方式
    • 获取正在运行的线程
    • 线程调度模型和线程优先级设置
      • 两种调度模型
      • 优先级设置
    • 线程控制
      • sleep
      • join
      • 守护线程
    • 线程生命周期


多线程

进程和线程

进程

进程:是正在运行的程序

  • 是系统进行资源分配和调用的独立单位

  • 每个进程都具有它自己的存储空间和系统资源

线程

线程:是进程中的单个顺序控制流,是一条执行路径

  • 单线程:一个进程如果只有一条执行路径,则称之为单线程程序

  • 多线程:一个进程如果有多条执行路径,则称之为多线程程序

继承Thread类方式实现多线程

  • 继承 Thread 类

  • 定义一个 MyThread 继承 Thread 类

  • 在 MyThread 类中重写 run() 方法

  • 创建 MyThread 类的对象

  • 启动线程

demo:

定义一个名字为MyThread的类继承Thread类,重新里面的run方法

package com.itxs.demo01;

/**
 * @Classname : MyThread
 * @Description : TODO 自定义线程 - 继承Thread类
 * @Author : lin_refuel@qq.com
 */
public class MyThread extends Thread {
    @Override
    // 当线程被启动时,会自动调用run方法
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("i = " + i);
        }
    }
}

创建测试类demo01

package com.itxs.demo01;

/**
 * @Classname : demo01
 * @Description : TODO
 * @Author : lin_refuel@qq.com
 */
public class demo01 {
    public static void main(String[] args) {
         // 创建线程对象
        MyThread mt01 = new MyThread();
        MyThread mt02 = new MyThread();
        MyThread mt03 = new MyThread();
         // 通过start方法来启动多线程
        mt01.start();
        mt02.start();
        mt03.start();
    }
}

运行结果:每个线程里面都是执行三次循环,并没有顺序,而是谁抢到谁执行,
在这里插入图片描述

设置线程名字的两个方式

  1. 调用方法setName()来设置线程名字
  2. 通过构造方法来设置线程名字

demo:

自定义的线程类

package com.itxs.demo01;

/**
 * @Classname : MyThread
 * @Description : TODO 自定义线程 - 继承Thread类
 * @Author : lin_refuel@qq.com
 */
public class MyThread extends Thread {
    // 无参构造
    public MyThread() {
        super();
    }

    /**
     * 带参数构造,设置每个线程名字
     * @param name 名字
     */
    public MyThread(String name) {
        super(name);
    }

    @Override
    // 当线程被启动时,会自动调用run方法
    public void run() {
        for (int i = 0; i < 3; i++) {
            // this当前类,getName表示获取当前类的名字
            System.out.println(this.getName() + " i = " + i);
        }
    }
}

测试类demo01

package com.itxs.demo01;

/**
 * @Classname : demo01
 * @Description : TODO
 * @Author : lin_refuel@qq.com
 */
public class demo01 {
    public static void main(String[] args) {
         // 创建线程对象
        MyThread mt01 = new MyThread("线程01");
        MyThread mt02 = new MyThread("线程02");
        MyThread mt03 = new MyThread();
        // 设置每个线程的名字的方法setName();
//        mt01.setName("线程01");
//        mt02.setName("线程02");
        mt03.setName("线程03");
         // 通过start方法来启动多线程
        mt01.start();
        mt02.start();
        mt03.start();
    }
}

运行结果:
在这里插入图片描述

获取正在运行的线程

调用下面Thread类中方法,可以获取当前正在运行对象

Thread.currentThread()

main也是一个线程,设置main线程名字,没有办法通过this.getName和this.setName进行设置,只能通过上面的Thread类中方法进行设置获取

demo:

注意run方法中,输出每个线程名字的地方调用了Thread.currentThread()

package com.itxs.demo01;

/**
 * @Classname : MyThread
 * @Description : TODO 自定义线程 - 继承Thread类
 * @Author : lin_refuel@qq.com
 */
public class MyThread extends Thread {
    // 无参构造
    public MyThread() {
        super();
    }

    /**
     * 带参数构造,设置每个线程名字
     * @param name 名字
     */
    public MyThread(String name) {
        super(name);
    }

    @Override
    // 当线程被启动时,会自动调用run方法
    public void run() {
        for (int i = 0; i < 3; i++) {
            // this当前类,getName表示获取当前类的名字
           // System.out.println(this.getName() + " i = " + i);
             System.out.println(Thread.currentThread().getName() + " i = " + i);
        }
    }
}

测试类demo01: 注意main线程获取的

package com.itxs.demo01;

/**
 * @Classname : demo01
 * @Description : TODO
 * @Author : lin_refuel@qq.com
 */
public class demo01 {
    public static void main(String[] args) {
         // 创建线程对象
        MyThread mt01 = new MyThread("线程01");
        MyThread mt02 = new MyThread("线程02");
        MyThread mt03 = new MyThread();
        // 设置每个线程的名字的方法setName();
//        mt01.setName("线程01");
//        mt02.setName("线程02");
        mt03.setName("线程03");
         // 通过start方法来启动多线程
        mt01.start();
        mt02.start();
        mt03.start();
        // 获取正在运行的线程对象
        Thread.currentThread().setName("主线程");// 设置main线程名字
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "i = " + i);
        }
    }
}

运行结果:
在这里插入图片描述

线程调度模型和线程优先级设置

两种调度模型

  • 两种线程调度模型

    • 分时调度模型:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间

    • 抢占调度模型:优先让优先级高的线程使用 CPU,如果线程的欧优先级相同,那么随机选择一个,优先级高的线程获取的 CPU 占用时间会相对多一些

    Java 使用的是抢占式的调度模型

优先级设置

Thread 类中设置和获取线程优先级的方法

 getPriority()//返回次线程的优先级
 setProiority()//更改次线程的优先级

demo:

创建一个名字为MyThread类继承Thread类

package com.itxs.demo01;

/**
 * @Classname : MyThread
 * @Description : TODO 自定义线程 - 继承Thread类
 * @Author : lin_refuel@qq.com
 */
public class MyThread extends Thread {
    // 无参构造
    public MyThread() {
        super();
    }

    /**
     * 带参数构造,设置每个线程名字
     * @param name 名字
     */
    public MyThread(String name) {
        super(name);
    }

    @Override
    // 当线程被启动时,会自动调用run方法
    public void run() {
        for (int i = 0; i < 50; i++) {
            // this当前类,getName表示获取当前类的名字
           // System.out.println(this.getName() + " i = " + i);
             System.out.println(Thread.currentThread().getName() + " i = " + i);
        }
    }
}

测试类demo02 - 查看优先级高的线程是否能更快执行完

package com.itxs.demo01;

/**
 * @Classname : demo02
 * @Description : TODO 线程优先级测试运行结果
 * @Author : lin_refuel@qq.com
 */
public class demo02 {
    public static void main(String[] args) {
         // 创建线程
        MyThread mt01 = new MyThread("线程01");
        MyThread mt02 = new MyThread("线程02");
        MyThread mt03 = new MyThread("线程03");
         // 设置每个线程优先级
        mt01.setPriority(Thread.MIN_PRIORITY);// 优先级低
        mt02.setPriority(Thread.NORM_PRIORITY);// 优先级不变
        mt03.setPriority(Thread.MAX_PRIORITY); // 优先级最高
        // 输出每个线程优先级
//        System.out.println(mt01.getPriority());//1
//        System.out.println(mt02.getPriority());//5
//        System.out.println(mt03.getPriority());//10
        // 开启线程
        mt01.start();
        mt02.start();
        mt03.start();
    }
}

运行结果: 线程mt03比其他两个线程运行快一点,仅仅一点

线程控制

sleep

sleep:使当前正在执行的线程停留指定的毫秒数

demo:案例:华山论剑

定义一个MyThread类继承Thread类

package com.itxs.demo02;

/**
 * @Classname : MyThread
 * @Description : TODO
 * @Author : lin_refuel@qq.com
 */
public class MyThread extends Thread {
    public MyThread() {
        super();
    }

    // 初始化线程名字的构造方法
    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 1; i <= 20; i++) {
            System.out.println(Thread.currentThread().getName() + "打出了第" + i + "招");
            // 调用sleep使其线程执行一次循环后停留1秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

sleeptest测试类

package com.itxs.demo02;

/**
 * @Classname : sleepTest
 * @Description : TODO sleep测试类
 * @Author : lin_refuel@qq.com
 */
public class sleepTest {
    public static void main(String[] args) {
        // 创建线程对象
        MyThread mt01 = new MyThread("黄固");
        MyThread mt02 = new MyThread("欧阳锋");
        MyThread mt03 = new MyThread("段智兴");
        MyThread mt04 = new MyThread("洪七公");
        // 开启线程
        mt01.start();
        mt02.start();
        mt03.start();
        mt04.start();
    }
}

join

join:等待线程结束

package com.itxs.demo03;

/**
 * @Classname : MyThread
 * @Description : TODO 自定义线程类 - 继承Thread类
 * @Author : lin_refuel@qq.com
 */
public class MyThread extends Thread {
    public MyThread() {
        super();
    }
    // 设置线程名字
    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName()+"报数:"+i);
        }
    }
}

test:测试类,注意join的使用,需要抛出异常

package com.itxs.demo03;

/**
 * @Classname : test
 * @Description : TODO
 * @Author : lin_refuel@qq.com
 */
public class test {
    public static void main(String[] args) throws InterruptedException {
         // 三个人报数,第一个人报完数后,其他人才能报数
        MyThread mt01 = new MyThread("1号");
        MyThread mt02 = new MyThread("2号");
        MyThread mt03 = new MyThread("3号");
        // 开始报数
        mt01.start();
        mt01.join();//等待第一个人报数完毕
        mt02.start();
        mt03.start();
    }
}

守护线程

setDaemon(boolean on)

将此线程标记为守护进程,当运行线程都是守护线程时,JVM 将退出

个人理解:主线程里面运行结束,守护线程不会继续执行

例子:老板带三个员工吃饭,老板吃饱后,员工不能继续吃了

demo:

定义MyThread类继承Thread类

package com.itxs.demo04;

/**
 * @Classname : MyThread
 * @Description : TODO
 * @Author : lin_refuel@qq.com
 */
public class MyThread extends Thread {
    public MyThread() {
        super();
    }

    // 设置线程对象名字
    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 1; i <= 50; i++) {
            System.out.println(Thread.currentThread().getName() + "正在吃" + i + "口");
        }
    }
}

定义三个线程设置为守护线程,进行测试,注意守护线程设置方式

package com.itxs.demo04;

/**
 * @Classname : test
 * @Description : TODO
 * @Author : lin_refuel@qq.com
 */
public class test {
    public static void main(String[] args) {
        // 创建三个工人线程
        MyThread mt01 = new MyThread("1号工人");
        MyThread mt02 = new MyThread("1号工人");
        MyThread mt03 = new MyThread("1号工人");
        System.out.println("吃饭了");

        // 三个工人线程设置为守护线程,老板说吃饱了,工人就不继续吃了
        mt01.setDaemon(true);
        mt02.setDaemon(true);
        mt03.setDaemon(true);
        mt01.start();
        mt02.start();
        mt03.start();
        // 主线程:作为老板
        Thread.currentThread().setName("老板");
        for (int i = 1; i <5; i++) {
            System.out.println(Thread.currentThread().getName() + "正在吃第" + i + "口");
        }
        System.out.println("老板说吃饱了,咱们走吧");
    }
}

线程生命周期

  • 新建:创建线程对象(通过 start() 进入下一个环节)

  • 就绪:有执行资格,没有执行权(抢占 CPU 的执行权)

  • 运行:有执行资格,有执行权(可能被其他线程抢走 CPU 的执行权,则回到就绪状态,若遇到阻塞式方法,则失去运行权和执行这个,等待,当阻塞方法调用结束之后,回到就绪状态)

  • 死亡:线程死亡,成为垃圾

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

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

相关文章

【算法每日一练]-dfs (保姆级教程 篇9) #俄罗斯方块 #ABC Puzzle #lnc的工资

目录 今日知识点&#xff1a; 二维图形的状态压缩&#xff0c;存下所有的合法状态然后暴力遍历 dfs的优化剪枝 二项式定理 俄罗斯方块 ABC Puzzle lnc的工资 俄罗斯方块 322D 题意&#xff1a;在4*4方格中分别给出3个俄罗斯方块&#xff0c;问是否可以经过旋转&#xf…

TOP刊竟一个月有结果,连中两篇,感觉投了就要!简直性价比天花板!

CEJ 期刊评说 网 友 辣 评 评说1&#xff1a;审稿很快&#xff0c;编辑应该就给审稿人20天审稿&#xff0c;投过两次都特别快&#xff01; 评说2&#xff1a;确实是性价比天花板&#xff0c;文章连续被老牌的一、二、三区期刊拒&#xff0c;多亏了 CEJ把我捞了起来&#xf…

IPv6组播技术--MLDv2

MPLDv1工作机制 IPv6组播网络中RouterA和RouterB连接主机网段,在主机网段上有HostA、HostB、HostC三个接收者。假设HostA和HostB想要接收发往组播组G1的数据,HostC想要接收发往组播组G2的数据。 查询器选举机制 当一个网段内有多台IPv6组播路由器时,由于它们都可以接收到…

mysql进阶 - 存储过程

目录 1. 用途&#xff1a; 2. 相关语法 2.1 创建 2.1.1 语法 2.1.2 示例 2.2 查看存储过程 2.3 调用 2.4 修改存储过程 2.5 删除存储过程 1. 用途&#xff1a; 存储过程广泛存在于一些遗留系统&#xff0c;可以减少代码的编写。而近些年&#xff0c;存储过程很少再用…

论文阅读_训练大模型用于角色扮演

英文名称: Character-LLM: A Trainable Agent for Role-Playing 中文名称: 角色-LLM&#xff1a;训练Agent用于角色扮演 文章: [https://arxiv.org/abs/2310.10158](https://arxiv.org/abs/2310.10158) 作者: Yunfan Shao, Linyang Li, Junqi Dai, Xipeng Qiu 机构: 复旦大学…

制作 Kali 可启动 USB 驱动器

Kali USB驱动器&#xff0c;轻松安全&#xff0c;获取最新镜像&#xff0c;开始强大的安全测试&#xff01; Kali 可启动 USB 驱动器的优点&#xff1a; 不会更改主机系统的硬盘驱动器或已安装的操作系统&#xff0c;并且要返回正常操作&#xff0c;您只需删除“Kali Live”U…

31 树的存储结构二

DIsplay() 递归显示 :图示 求树的高度时&#xff0c;递归的技巧 在递归的过程中&#xff1a;ret单独和任意一个子树的子高度比较&#xff0c;如果ret<max&#xff0c;retmax ------------- 注意&#xff1a;组织链表和子链表的【元素类型】都是TLNode* 链表都要先通过TLNod…

HTB-SAU

信息收集 # cat port.nmap # Nmap 7.94 scan initiated Thu Jan 11 19:26:51 2024 as: nmap -sS --min-rate 10000 -p- -oN port.nmap 10.10.11.224 Nmap scan report for 10.10.11.224 (10.10.11.224) Host is up (0.28s latency). Not shown: 65531 closed tcp ports (r…

pymssql 报错误解决办法:20002, severity 9

错误 解决办法 python3.6&#xff0c;安装pymssql低版本&#xff08;pymssql-2.1.5-cp36-cp36m-win32.whl&#xff09;

Feature Fusion for Online Mutual KD

paper&#xff1a;Feature Fusion for Online Mutual Knowledge Distillation official implementation&#xff1a;https://github.com/Jangho-Kim/FFL-pytorch 本文的创新点 本文提出了一个名为特征融合学习&#xff08;Feature Fusion Learning, FFL&#xff09;的框架&…

流量预测中文文献阅读(郭郭专用)

目录 基于流量预测的超密集网络资源分配策略研究_2023_高雪亮_内蒙古大学&#xff08;1&#xff09;内容总结&#xff08;2&#xff09;流量预测部分1、数据集2、结果对其中的一个网格的CDR进行预测RMSE和R2近邻数据和周期数据对RMSE的影响 &#xff08;3&#xff09;基于流量预…

点餐新体验:老板自研扫码点餐小程序的成果

为了提高餐厅的效率和顾客的用餐体验&#xff0c;餐饮店老板们纷纷开始探索新的技术手段。其中&#xff0c;扫码点餐小程序就是一种非常受欢迎的解决方案。 扫码点餐小程序是一种基于微信小程序开发的餐饮点餐系统&#xff0c;它通过扫描桌码或菜品二维码&#xff0c;实现快速点…

ElasticSearch概述+SpringBoot 集成 ES

ES概述 开源的、高扩展的、分布式全文检索引擎【站内搜索】 解决问题 1.搜索词是一个整体时&#xff0c;不能拆分&#xff08;mysql整体连续&#xff09; 2.效率会低&#xff0c;不会用到索引&#xff08;mysql索引失效&#xff09; 解决方式 进行数据的存储&#xff08;只存储…

【面试宝典】图解ARP协议、TCP协议、UDP协议

一、ARP协议 二、TCP协议 三、UDP协议 四、TCP和UDP的区别

基于Springboot+uniapp的美容美发预约、会员管理、充值小程序(有文档、Java毕业设计)

大家好&#xff0c;我是DeBug&#xff0c;很高兴你能来阅读&#xff01;作为一名热爱编程的程序员&#xff0c;我希望通过这些教学笔记与大家分享我的编程经验和知识。在这里&#xff0c;我将会结合实际项目经验&#xff0c;分享编程技巧、最佳实践以及解决问题的方法。无论你是…

【LabVIEW FPGA入门】LabVIEW FPGA 实现SPI通信协议

该实现由两个组件组成&#xff1a;在 LabVIEW FPGA 中实现的 SPI 协议以及用于从主机 PC 或实时控制器与 FPGA 进行通信的 LabVIEW 主机接口。该架构允许从单个主机程序控制多个 SPI 端口&#xff0c;同时仍然允许定制 FPGA VI 以进行其他数据采集和处理。该实现不使用任何DMA&…

[DL]深度学习_Feature Pyramid Network

FPN结构详解 目录 一、概念介绍 二、结构详解 1、对比试验 2、特征图融合 3、结构详解 4、不同尺度预测 5、Proposal映射到预测特征层 一、概念介绍 Feature Pyramid Network (FPN)是一种用于目标检测和语义分割的神经网络架构。它的目标是解决在处理不同尺度的图像时…

C语言天花板——指针(进阶3)

篇接上文(http://t.csdnimg.cn/Tl42h)&#xff0c;今天我们来讲一些有趣的关于指针的问题&#x1f6a2;&#x1f6a2;&#x1f6a2; 首先我们来看个代码&#xff1a; int main() {//一维数组int a[] { 1,2,3,4 };//4个元素&#xff0c;每个元素使int类型(4个字节)printf(&qu…

03.neuvector之组的划分逻辑

neuvector之组的划分逻辑 原文链接,欢迎大家关注我的github账号 一、组的定义 NeuVector 会自动从正在运行的应用程序中创建组。这些组以前缀‘nv‘开头。您也可以使用 CRD 或 REST API 手动添加它们&#xff0c;并且可以在任何模式下创建、发现、监视或保护。网络和响应规则需…

【嵌入式移植】3、编译U-Boot

编译U-Boot 0 U-Boot及本文所选硬件1 获取U-Boot源码2 获取工具链3 BL314 编译4.1 yylloc4.2 u_boot_dtsi 5 烧写6 上电验证 0 U-Boot及本文所选硬件 Das U-Boot&#xff0c;全称 Universal Boot Loader&#xff0c;是遵循GPL条款的开放源码项目。U-Boot的作用是系统引导。U-B…