Java中的多线程

进程和线程的概念

进程是应用程序的执行实例有独立的内存空间和系统资源。

线程是进程中执行运算的最小单位,可完成一个独立的顺序控制流程
一。一个进程可以包含多个线程,每个线程都独立执行特定的任务,
是CPU调度和分派的基本单位。

多线程的概念:

  • 如果在一个进程中同时运行了多个线程,用来完成不同的工作,则称之为“多线程”
  • 多个线程交替占用CPU资源,而非真正的并行执行

多线程的好处:

  • 充分利用CPU的资源
  • 简化编程模型
  • 带来良好的用户体验

主线程:
Thread类

Java提供了java.lang.Thread类支持多线程编程

主线程

  • main()方法即为主线程入口
  • 产生其他子线程的线程
  • 必须最后完成执行,因为它执行各种关闭动作
public static void main(String args[]) {
		Thread t= Thread.currentThread(); 
		System.out.println("当前线程是: "+t.getName()); 
		t.setName("MyJavaThread"); 
		System.out.println("当前线程名是: "+t.getName()); }

线程的创建和启动

在Java中,可以通过继承Thread类或实现Runnable接口来创建线程。
在这里插入图片描述

  1. 继承Thread类:
    I. 定义MyThread类继承Thread类
    ||. 重写run()方法,编写线程执行体
    |||. 创建线程对象,调用start()方法启动线程
public class MyThread extends Thread {
    public void run() {
        // 线程执行的代码
    }
}

// 创建并启动线程
MyThread thread = new MyThread();
thread.start();

补充:

多线程里的多个线程交替执行,而不是真正的“并行”。
线程每次执行时长由分配的CPU时间片长度决定。

  1. 实现Runnable接口:
    |.定义MyRunnable类实现Runnable接口
    ||.实现run()方法,编写线程执行体
    |||.创建线程对象,调用start()方法启动线程
public class MyRunnable implements Runnable {
    public void run() {
        // 线程执行的代码
    }
}
// 创建并启动线程
MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable);
thread.start();

调用线程的run()和start()方法的区别如下:

run()方法:直接调用线程对象的run()方法会在当前线程中执行该方法的代码,就像普通的方法调用一样。并不会创建新的线程,而是在当前线程中按顺序执行。所以只有主线程main一条执行路径。

start()方法:调用线程对象的start()方法会创建一个新的线程,并在新的线程中执行run()方法的代码。start()方法会启动线程的执行,然后立即返回,不会阻塞当前线程。所以具体执行过程有多条执行路径,主线程和子线程并行交替执行

总结来说,直接调用run()方法只会在当前线程中执行方法的代码,不会创建新的线程。而调用start()方法会创建新的线程,并在新线程中执行方法的代码。通常情况下,我们应该使用start()方法来启动线程,以实现多线程并发执行的效果。

比较两种创建线程的方式

继承Thread类:

  • 编写简单,可直接操作线程
  • 适用于单继承

实现Runnable接口

  • 避免单继承局限性
  • 便于共享资源

线程的状态

线程在生命周期中有多个状态:
线程共包括以下 5 种状态:

下面是使用Markdown语法写的嵌套列表:

线程共包括以下 5 种状态:

  1. 新建状态(New): 线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()

  2. 就绪状态(Runnable): 也被称为“可执行状态”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行。

  3. 运行状态(Running): 线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。

  4. 阻塞状态(Blocked): 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:

    • 等待阻塞 – 通过调用线程的wait()方法,让线程等待某工作的完成。
    • 同步阻塞 – 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。
    • 其他阻塞 – 通过调用线程的sleep()join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
  5. 死亡状态(Dead): 线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

线程调度的常用方法

线程调度指操作系统或Java虚拟机按照特定机制为多个线程分配CPU的使用权。Java提供了一些常用的线程调度方法:

方法
void setPriority(int newPriority)更改线程的优先级
static void sleep(long millis)在指定的毫秒数内让当前正在执行的线程休眠
void join()等待该线程终止
static void yield()暂停当前正在执行的线程对象,并执行其他线程
void interrupt()中断线程
boolean isAlive()测试线程是否处于活动状态
  1. 线程优先级
    • 线程优先级由1~10表示,1最低,默认优先级为5
    • 优先级高的线程获得CPU资源的概率较大
public static void main(String[] args) {
		Thread t1 = new Thread(new MyThread(),"线程A");
        Thread t2 = new Thread(new MyThread(),"线程B");
		t1.setPriority(Thread.MAX_PRIORITY);
		t2.setPriority(Thread.MIN_PRIORITY);
       //省略代码……
	}}

  1. static void sleep(long millis):使当前线程暂停执行一段时间。
    • millis为休眠时长,以毫秒为单位
    • 调用sleep()方法需处理InterruptedException异常
try {
    Thread.sleep(1000); // 暂停1秒
} catch (InterruptedException e) {
    e.printStackTrace();
}
  • yield():暂停当前正在执行的线程,让出CPU资源给其他线程。
Thread.yield();
  1. join():等待其他线程执行完毕再继续执行。
  • public final void join()

  • public final void join(long mills)

  • public final void join(long mills,int nanos)

    • millis:以毫秒为单位的等待时长
    • nanos:要等待的附加纳秒时长
    • 需处理InterruptedException异常
Thread thread1 = new Thread();
Thread thread2 = new Thread();

thread1.start();
thread2.start();

try {
    thread1.join(); // 等待thread1执行完毕
    thread2.join(); // 等待thread2执行完毕
} catch (InterruptedException e) {
    e.printStackTrace();
}

5.public static void yield()线程的礼让

  • 暂停当前线程,允许其他具有相同优先级的线程获得运行机会
  • 该线程处于就绪状态,不转为阻塞状态

只是提供一种可能,但是不能保证一定会实现礼让

public class MyThread implements Runnable{
     public void run(){
          for(int i=0;i<5;i++){
    	System.out.println(Thread.currentThread().
              getName()+"正在运行:"+i);
    	 if(i==3){
    	    System.out.print("线程礼让:");
	    Thread.yield();	
                    } } }}

线程的同步

多个线程访问共享资源时可能会出现数据不一致的问题,需要使用同步机制来保证线程安全。

  1. synchronized关键字:可以修饰方法或代码块,确保同一时间只有一个线程执行。
    方法:
    在这里插入图片描述
    代码块:
    在这里插入图片描述
public synchronized void synchronizedMethod() {
    // 同步的方法
}


public void someMethod() {
    synchronized (this) {
        // 同步的代码块
       
    }
}
  1. Lock对象:使用Lock接口的实现类来实现同步。
Lock lock = new ReentrantLock();

lock.lock(); // 获取锁

try {
    // 同步的代码块
} finally {
    lock.unlock(); // 释放锁
}

多个并发线程访问同一资源的同步代码块时

  1. 同一时刻只能有一个线程进入synchronized(this)同步代码块
  2. 当一个线程访问一个synchronized(this)同步代码块时,其他synchronized(this)同步代码块同样被锁定
  3. 当一个线程访问一个synchronized(this)同步代码块时,其他线程可以访问该资源的非synchronized(this)同步代码

Java中常见的线程安全类型及其比较:

  1. ArrayList vs. Vector:

    • ArrayList是非线程安全的类型,适用于单线程环境下的操作。
    • Vector是线程安全的类型,适用于多线程环境下的操作。Vector的方法使用了synchronized关键字进行同步,保证了线程安全。
      在这里插入图片描述
  2. Hashtable vs. HashMap:

    • Hashtable是线程安全的类型,适用于多线程环境下的操作。Hashtable的方法使用了synchronized关键字进行同步,保证了线程安全。
    • HashMap是非线程安全的类型,适用于单线程环境下的操作。HashMap的方法没有进行同步,不保证线程安全。

在这里插入图片描述

  1. StringBuffer vs. StringBuilder:
    • StringBuffer是线程安全的类型,适用于多线程环境下的操作。StringBuffer的方法使用了synchronized关键字进行同步,保证了线程安全。
    • StringBuilder是非线程安全的类型,适用于单线程环境下的操作。StringBuilder的方法没有进行同步,不保证线程安全。

需要注意的是,虽然线程安全的类型在多线程环境下可以保证数据的一致性和正确性,但在性能上可能会有一定的开销。非线程安全的类型在多线程环境下需要额外的同步措施来保证数据的安全性。因此,在选择使用哪种类型时,需要根据具体的需求和场景进行权衡和选择。
在这里插入图片描述

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

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

相关文章

2023年全国职业院校技能大赛软件测试赛题—单元测试卷⑥

单元测试 一、任务要求 题目1&#xff1a;根据下列流程图编写程序实现相应分析处理并显示结果。返回结果“ax&#xff1a;”&#xff08;x为2、3或4&#xff09;&#xff1b;其中变量x、y均须为整型。编写程序代码&#xff0c;使用JUnit框架编写测试类对编写的程序代码进行测试…

开发知识点-RabbitMQ

RabbitMQ 下载与介绍权限了解消息状态rabbitmqctl命令与操作配置常见错误常见问题日志 poc-yaml-rabbitmq-default-password 下载与介绍 RabbitMQ是一个使用Erlang语言开发 开源的消息中间件项目&#xff08;Message Broker&#xff09;&#xff0c; 采用Mozilla Public Licen…

SpringBoot用MultipartFile.transferTo传递相对路径的问题

问题描述&#xff1a; 打算给自己的项目添加一个上传文件保存功能&#xff0c;于是我使用MultipartFile.transferTo()来完成这个功能&#xff0c;由于我的项目要部署到服务器&#xff0c;所以我使用了相对路径把上传的文件保存到当前项目的工作目录下&#xff0c;但是报错了&am…

如何在 Windows 中使用Copilot AI

Windows Copilot 是 Windows 中的一个新功能&#xff0c;它可以让你与一个智能助理进行对话&#xff0c;获取信息&#xff0c;执行任务&#xff0c;甚至创造内容。Windows Copilot 使用了 Bing Chat 的技术&#xff0c;它是一个基于 OpenAI 的 GPT-4 模型的聊天机器人。 目录 …

关于树结构的数据的权限控制的算法

树结构的权限控制分两种:1、逐层加载&#xff1b;2、一次性加载 一、逐层加载 涉及的表结构 表名 T_PLAN 表字段 字段类型 是否必 须字段 说明 ID VARCHAR2(50) Y 主键 PARENT_ID VARCHAR2(50) Y 父项节点ID&#xff0c;默认根节点的父节点ID’-1’ TREEPATH VA…

vue3的福音框架arco.design

前言&#xff1a; 在vue2于2023年底正式宣布不在维护&#xff0c;vue3使用越来越频繁的时刻&#xff0c;我们实现项目的辅助框架也越来越多。element, iview, antd 等经典框架继续风靡一时&#xff0c;不过也有很多好的框架&#xff0c;功能也强大&#xff0c;比如我们今天说的…

ISO 11519-2 开环低速 CAN 网络(10K~125Kbps)

ISO 11519-2 标准的物理框图如下图 可理解为一个低速开环 CAN 总线网络&#xff1b;CAN 开环总线网络允许总线最大长度为 1km;最高速度为 125Kbps;这里的两根线是独立的&#xff0c;每根线上串联一个 2.2kΩ 的电阻&#xff1b;节点就是不同的设备&#xff0c;连接到一个开环总…

Mac上使用phpstudy+vscode配置PHP开发环境

使用的工具&#xff1a; 1、系统版本 2、vs code code 3、phpstudy_pro 一、下载vs code code以及必要的插件 1、vs code下载 点击vs code官网下载 选择对应的版本&#xff0c;一般电脑会自动识别对应的版本&#xff0c;点击下载&#xff0c;然后傻瓜式安装&#xff01; 2…

万字长文 详细讲述 计算机网络层

文章目录 网络层网络层的几个重要概念网络层的两个层面 网际协议 IP虚拟互连网络IP 地址IP 地址及其表示方法IP 地址与 MAC 地址地址解析协议 ARPIP 数据报的格式 IP层转发分组过程基于终点的转发最长前缀匹配 网际控制报文协议 ICMPICMP 报文的种类ICMP 的应用举例IPv6 的基本…

Leetcode 494 目标和

题意理解&#xff1a; 给你一个非负整数数组 nums 和一个整数 target 。 向数组中的每个整数前添加 或 - &#xff0c;然后串联起所有整数&#xff0c;可以构造一个 表达式 &#xff1a; 例如&#xff0c;nums [2, 1] &#xff0c;可以在 2 之前添加 &#xff0c;在 1 之前添…

js更新地址栏,但是不刷新页面

记录一下第一次遇到更新地址栏但是不刷新页面的需求 有时候会遇到一些需求&#xff0c;比如复制地址&#xff0c;分享给别人 希望也保留筛选条件&#xff0c;但是之前做的时候筛选条件存储到的状态管理工具里面了&#xff0c;地址栏没有&#xff0c;所以为了更快的实现效果&am…

如何下载“ubuntu”在win10系统?

一、下载 企业开源和 Linux |Ubuntu的

解决jenkins需要jdk11,项目需要jdk8的问题

思路&#xff1a;jdk8 采用解压缩模式&#xff0c;jdk11采用安装模式&#xff0c;然后在jenkins中指定jdk路径 下载解压缩jdk8 https://www.oracle.com/java/technologies/downloads/#java8 解压缩&#xff1a;jdk-8u391-linux-i586.tar.gz /lib/ld-linux.so.2: bad ELF inte…

Realm Management Extension领域管理扩展之颗粒保护检查

本节描述了RME引入的颗粒保护检查。颗粒保护检查使得能够在不同的物理地址空间之间动态分配内存区域。 本节将向您介绍以下功能: 颗粒保护表的结构用于颗粒保护检查的故障报告区域在物理地址空间之间的过渡正如在物理地址一节中所述,RME提供了四个物理地址空间。以下图表显示…

搭建 MyBatis 环境

目录 1.添加依赖 2.数据库连接配置 3.配置XML路径 4.下载插件MyBatisX 5.如何使用 6.示例 1.添加依赖 创建新项目时添加两个依赖: MyBatis Framewrok 和 MySQL Driver 。 如果是在已经创建好的项目中配置mybatis环境。需要先下载一个插件&#xff1a;EditStarters 。 然…

JavaScript复习小案例

JavaScript实现简易留言板 效果图 完整代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>留言板</title><style>body {background-color: #f4f4f4;}/* 外部容器样式设置 */.wrapper {width: 400px;heigh…

探索 TCP 与 UDP:网络通信的两门学派(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

Vue3组件库 -- element plus 树形选择器组件怎样显示已有的树形菜单?

<el-tree-selectv-model"form.topmneu":data"tableData":props"{ label: title, value: id }":render-after-expand"false"style"width: 100%"check-strictly/> 添加 :props "{ lable : 字段名 , value: 字段…

Java并发之同步二:Java并发工具类

一、CountDownLatch &#xff08;1等多汇总、多等1 开关&#xff09; countdownlatch 底层原理&#xff0c;定义锁资源&#xff1a;0&#xff0c;当资源为0才叫拿到锁&#xff0c;所以countdownlatch也叫做倒数器&#xff0c;拿锁的时候判断是不是0&#xff0c;不是就park&…

NumPy 数据操作实用指南:从基础到高效(下)

文章接上篇&#xff1a; In [53]: from PIL import Image In [60]: dog Image.open(./dog.jpg) dog . . . In [61]: dog_datanp.array(dog) # 图片数据是ndarray # 彩色照片三维&#xff1a;高度&#xff0c;宽度&#xff0c;像素&#xff08;表示不同颜色&#xff09;&…