Javase | 多线程

目录:

    • 1.程序
    • 2.进程
    • 3.线程
    • 4.多线程
    • 5.自定义线程类 :
      • 5.1 继承Thread类
      • 5.2 实现Runnable接口
    • 6.多线程的生命周期及状态转换
      • 新建状态 (New)
      • 就绪状态 (Runnable)
      • 运行状态 (Running)
      • 阻塞状态 (Blocked)
      • 死亡状态 (Terminated)
    • 7.多线程的调度
      • 线程的优先级
      • 线程的休眠
      • 线程的让步
      • yield() 和 sleep() 的区别
    • 8.多线程同步和通信
      • 8.1 多线程的同步
      • 8.2 多线程通信

1.程序

程序:是对数据描述操作的。 代码的集合。是应用程序执行脚本静态

2.进程

  • 在一个操作系统中,每个 独立执行程序 都可以称为一个 进程,也就是 正在运行的程序 ,强调了 运行 的状态。
  • 目前大部分计算机安装的都是多任务操作系统,即能同时执行多个应用程序
  • 表明看进程是并发执行的,实际上这些 进程并不是同时运行的,操作系统会为每一个进程分配一段有限的CPU时间,CPU在这段时间执行某个进程,在下段时间切换到另一个进程

3.线程

  • 在一个 进程 ( 正在运行的程序 )中可以有 多个 “执行单元” 同时运行它们可以看做 程序执行的一条条路径,被称为 线程
  • 操作系统每一个进程至少存在一个线程
  • 在一个Java程序启动时会产生一个进程,该进程默认创建。一个线程,在该线程上运行main()方法中的代码

4.多线程

  • 如果希望 程序中实现“多段程序代码” 交替运行的效果,则 需要创建多个线程,即 多线程 程序。
  • 单线程执行时只有一个路径CPU就一直按按照这个路径执行多线程多个路径CPU在多个路径上切换执行

5.自定义线程类 :

  • 继承Thread类重写run( )方法,在run方法中实现线程中的代码。
  • 实现Runnable接口,同样要 重写run( )方法实现在线程上的代码。

5.1 继承Thread类

  • 继承Thread类创建线程步骤 为:

    定义类,声明继承Thread类

    重写Thread的run( )方法,run()方法方法体线程对应的子任务

    创建自定义类的对象,调用start( )方法。start( )方法的作用启动线程调用run( )方法

  • 由于线程的运行顺序随机调度的,因此会出现不同的结果

  • public class Demo {public static void main(String[] args) {//此代码为多线程"的程序System.out.println("Demo类的主线程正在运行。");//创建两个线程MyThread myThread1 = new MyThread();MyThread myThread2 = new MyThread();//启动线程myThread1.start();myThread2.start();System.out.println("Demo的主线程运行结束。");}
    }class MyThread extends Thread{@Overridepublic void run() {System.out.println("线程"+Thread.currentThread().getName()+"的run()方法正在运行。");}
    }
    

5.2 实现Runnable接口

  • 通过继承Thread类有一定局限性,因为Java只支持单继承一旦继承了某个父类就不能再继承Thread类,这时可通过实现Runnable接口来避免这个问题

  • Thead类提供了另一个 构造方法 Thread(Runable target)Runnable接口中只有一个run( )方法,因此只需传递一个实现Runnable接口的实例对象就能创建线程

    创建的线程会调用实现Runnable接口中的run( )方法,不用调用Thread类的 run( ) 方法。

  • 实现Runnable接口创建线程步骤 为:

    定义类,实现Runnable接口

    重写Runnable接口的run( )方法,run()方法方法体线程对应的子任务

    创建自定义类的对象,创建Thread类,Thread类的构造方法的参数为“自定义的对象”

    调用 start( ) 方法,开始多线程

    调用start( )方法。start( )方法的作用启动线程调用run( )方法

    public class Demo2 {public static void main(String[] args) {//此代码为多线程的程序System.out.println("Demo2类的主线程正在运行。");//创建自定义的实现了Runnable接口的类MyThread2 obj = new MyThread2();//创建两个线程,第二个参数为线程指定的名称Thread t1 = new Thread(obj, "Thread 1 ");Thread t2 = new Thread(obj, "Thread 2 ");//启动线程t1.start();t2.start();System.out.println("Demo2类的主线程运行结束。");}
    }class MyThread2 implements Runnable {@Overridepublic void run() {System.out.println("线程"+Thread.currentThread().getName()+"的run()方法正在运行。");}
    }
    

6.多线程的生命周期及状态转换

  • Thread对象创建完成时,线程的生命周期就开始了。当run()方法中代码正常执行完毕抛出一个未捕获的异常或错误时,线程的生命周期将结束

  • 线程生命周期分为五个阶段

    新建状态 (New)

    就绪状态 (Runnable)

    运行状态 (Running)

    阻塞状态 (Blocked)

    死亡状态 (Terminated)

新建状态 (New)

  • 创建一个线程对象后该线程对象就处于新建状态。此时不能运行,和其他Java对象一样,仅为其分配了内存,没有任何线程的动态特征。

就绪状态 (Runnable)

  • 线程对象调用了start( )方法后,该线程就进入“就绪状态,此时具备了运行的条件,能获得CPU的使用权,还需要等待系统的调度。

运行状态 (Running)

  • 就绪状态线程获得了CPU的使用权开始执行run()方法,则线程处于运行状态。当一个线程启动后,它不可能一直处于运行状态

阻塞状态 (Blocked)

  • 一个正在执行的线程某些特殊情况下,如执行耗时的输入/输出操作时会放弃CPU的使用权,进入 阻塞状态。只有当引起 阻塞的原因被消除后线程才可以转入就绪状态

  • 当线程试图获取某个对象的 同步锁 时,如果该锁其他线程所持有时,线程会由运行状态转为阻塞状态

  • 当调用一个阻塞的IO方法,要等待这个阻塞的IO方法返回,此时 线程会由运行状态转为阻塞状态

  • 当线程调用了某个对象的wait()方法,此时 线程会由运行状态转为阻塞状态 。需要使用notify()方法唤醒该线程

  • 当线程调用了Thread的sleep(long millis)方法时,此时 线程会由运行状态转为阻塞状态等到休眠时间到了才能进行“就绪状态

  • 线程调用了另一个线程join()方法时,此时 线程会由运行状态转为阻塞状态,需要等新加入的线程运行结束后才能结束阻塞

死亡状态 (Terminated)

  • 当线程的run()方法中代码正常执行完毕或者抛出一个未捕获的异常或者错误时,线程进入死亡状态。线程将不在拥有运行的资格也不能再转化到其他状态

7.多线程的调度

  • Java虚拟机会按照特定的机制为程序中的 每个线程分配CPU的使用时间,这种机制被称为 线程的调度

  • 线程调度有两种模型 :①分时调度模型抢占式调度模型

    分时调度模型:所有线程轮流平均分配CPU时间

    抢占式调度模型:可运行池中优先级高的线程相同优先级的随机选择一个线程使其占用CPU,它失去了使用权之后,再随机选择其他线程

线程的优先级

  • 线程的优先级1-10之间的整数来表示,数字越大优先级越高。可以用Thread类中的 setPriority(int newPriority) 方法进行设置。优先级高的先运行,优先级低的后运行

  • public class Demo3 {public static void main(String[] args) {MaxP max = new MaxP();MinP min = new MinP();Thread maxT = new Thread(max, "优先级高的程序"); //设置了优先级,其先执行Thread minT = new Thread(min, "优先级低的程序"); //其后执行/*** 正常而言,优先级高的“线程”先执行,优先级低的“线程”后执行。*/maxT.setPriority(10); //设置优先级minT.setPriority(1);maxT.start();minT.start();System.out.println("主线程结束。");}
    }class MaxP implements Runnable {public static void main(String[] args) {System.out.println("主线程正在运行。");}@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName()+": "+i);}}
    }class MinP implements Runnable {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName()+": "+i);}}
    }
    

线程的休眠

  • 如果希望人为控制线程,使 线程暂停将CPU让给其他线程,可以使用sleep(long millis)

  • public class Demo4 {public static void main(String[] args) throws InterruptedException {System.out.println("主线程正在运行。");//创建自定义线程对象MyThread mt = new MyThread();//创建线程Thread thread = new Thread(mt);//启动线程thread.start();for (int i = 0; i < 10; i++) {if (i == 5) {//线程休眠,后进入阻塞状态,休眠结束后,重新进入“就绪状态”Thread.sleep(9000); //当i==5时Thead.sleep(),该for循环休眠了9秒}System.out.println("主线程输出: "+i);}System.out.println("主线程运行结束。");}
    }class MyThread implements Runnable {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println("MyThread的输出: "+i);}}
    }
    

线程的让步

  • 线程让步 可以通过yield()方法来实现,该方法和sleep()方法有点相似都可以让当前 “正在运行” 的线程暂停
  • 区别在于yield()方法不会阻塞该线程,它只是将线程转换为就绪状态,重新进入“线程排队”状态。
    sleep() 会让线程进入阻塞状态睡眠结束后,该线程才重新进入就绪状态,进行“线程排队”。

yield() 和 sleep() 的区别

  • 两个方法功能有点相似 : 都可以让当前“正在运行”的线程暂停最后使线程进入就绪状态,后进行“线程排队
  • yield() 方法不会阻塞该线程,它只是将线程转换为就绪状态,重新进入“线程排队”状态。
    sleep() 会让线程进入阻塞状态睡眠结束后,该线程才重新进入就绪状态,进行“线程排队”。
  • yield() 告诉操作系统当前线程愿意放弃CPU执行时间片,重新进入“就绪状态”,进行“线程排队”。但是否会马上执行该“就绪状态”的线程得看操作系统的分配了。
  • sleep() 使得该线程进入休眠状态,休眠中为“阻塞状态”。当休眠结束时,线程重新进入“就绪状态”,进行“线程排队”。

8.多线程同步和通信

8.1 多线程的同步

  • 多线程的并发执行虽然可以提高效率,但是当多个线程去访问同一个资源时,也会引发一些安全问题
    如:线程A读取资源A时,线程B正在修改资源A。那么线程A会读取到/该读取到修改之前的资源A,还是修改后的资源A呢?
    (可用多线程的同步避免此类问题

  • 多线程同步两种常用方法 :

    同步代码块synchronized(lock) { 操作共享资源代码块 }

    同步方法synchronized 返回值类型 方法名(参数列表)

  • //同步代码块例子
    public class Demo5 {  public static void main(String[] args) {//自定义线程对象SaleTicket sale = new SaleTicket();//创建四个线程,模拟四个窗口售票Thread t1 = new Thread(sale, "窗口1");Thread t2 = new Thread(sale, "窗口2");Thread t3 = new Thread(sale, "窗口3");Thread t4 = new Thread(sale, "窗口4");t1.start();t2.start();t3.start();t4.start();}}class SaleTicket implements Runnable {int num = 50;@Overridepublic void run() {while (true) {//创建“同步代码块”synchronized ("锁") {if (num > 0) {System.out.println(Thread.currentThread().getName() + "售出了第" + num + "号票。");num--;} else {System.out.println("票售完了。");break;}}}}
    }
    
  • public class Demo6 {public static void main(String[] args) {TicketThread2 t = new TicketThread2();Thread t1 = new Thread(t, "窗口1");Thread t2 = new Thread(t, "窗口2");Thread t3 = new Thread(t, "窗口3");Thread t4 = new Thread(t, "窗口4");t1.start();t2.start();t3.start();t4.start();}
    }class TicketThread2 implements Runnable {//总票数int num = 50;@Overridepublic void run() {while (true) {//调用售票的方法sale();if (num <= 0) {System.out.println("票卖完了。");break;}}}private synchronized void sale() { //该方法是同步的if (num > 0) {System.out.println(Thread.currentThread().getName()+"售出了"+num+"号票。"); //获得线程名字等配合其他信息使用num --;}}
    }
    

8.2 多线程通信

  • 线程通信 指的是一个线程完成了自己的任务时,要通知另外一个线程去完成另外一个任务

  • 要完成线程之间的通信,就需要控制多个线程按照一定的顺序轮流执行

  • Object类中提供了wait(), notify()notifyALL()方法用于解决线程之间的通信问题

  • 这三个方法的调用者都应该是同步锁对象,否则会抛出IllegalMonitorStateException异常

  • 方法名称功能描述
    void wait()使当前线程放弃同步锁进入等待,直到其他线程进入此同步锁,并调用notify()或notifyAll()方法唤醒该线程为止。
    void notify()唤醒同步锁上等待的第一个调用wait()方法的线程。
    void notifyAll()唤醒此同步锁上调用wait()方法的所有线程。

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

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

相关文章

你好!插值查找【JAVA】

1.初次相识 插值查找&#xff08;interpolation search&#xff09;是一种根据待查找关键字在有序数组中的大致位置决定查找范围的查找算法。插值查找与二分查找类似&#xff0c;区别在于插值查找对于待查找关键字在数组中的位置进行估计&#xff0c;从而更精准地定位到待查找关…

SpringBoot+mysql+vue实现大学生健康档案管理系统前后端分离

一、项目简介 本项目是一套基于SpringBoot实现大学生健康档案管理系统&#xff0c;主要针对计算机相关专业的正在做bishe的学生和需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目可以直接作为bishe使用。 项目都经过严格调试&#…

Android Studio新版UI介绍

顶部菜单栏 左侧主要菜单入口项目名称分支名称 展开之后&#xff0c;主要功能与原来菜单栏功能一样&#xff0c;最大的变化就是把setting独立出去了。 而项目名称这里&#xff0c;展开就可以看到打开的历史工程列表&#xff0c;可以直接新建工程&#xff0c;原来需要在项目名称…

git的相关实用命令

参看文章&#xff1a;https://blog.csdn.net/qq_21688871/article/details/130158888 http://www.mobiletrain.org/about/BBS/159885.html 1、git commit后&#xff0c;但发现文件有误&#xff0c;不想push(提交到本地库&#xff0c;回退到暂存区&#xff09; git reset --sof…

k8S 发布spring boot的jar包

在Kubernetes&#xff08;K8s&#xff09;上部署Spring Boot应用&#xff08;打包成jar文件&#xff09;的基本步骤如下&#xff1a; 1. 准备Spring Boot应用的Jar包 确保你的Spring Boot应用已经成功构建&#xff0c;生成了可执行的jar包。 2. 创建Docker镜像 为你的Sprin…

leetcode每日一题4

罗马数字转化为十进制整数 罗马数字包含以下七种字符: I&#xff0c; V&#xff0c; X&#xff0c; L&#xff0c;C&#xff0c;D 和 M。 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M …

locked1勒索病毒,刚攻击完海康威视系统,又再针对速达软件服务器攻击

导言&#xff1a; .locked、.locked1勒索病毒正成为数字安全的一大威胁。本文91数据恢复将深入介绍.locked、.locked1勒索病毒的特点、如何有效恢复被其加密的数据文件&#xff0c;以及预防这一数字噩梦的方法。如果您正在经历勒索病毒数据恢复的困境&#xff0c;我们愿意与您…

漏刻有时百度地图API实战开发(7)个性化地图加载瓦片空白和Echarts加载bmap元素跟踪重影

一、地图瓦片加载缓慢或者空白 在使用百度个性化地图时&#xff0c;出现地图瓦片加载缓慢或者空白 解决方案 1.替换百度地图API引入方式 <script type"text/javascript" src"https://api.map.baidu.com/api?v3.0&akI2428Rc4FDz00LSGUYfISLcbPsxOfjx…

Prometheus-IDC环境网络设备监控

均采用docker-compose部署Prometheus基础环境 部署参考https://blog.csdn.net/ht9999i/article/details/134733793?spm1001.2014.3001.5501 开头 一.部署Prometheus # cat docker-compose.yml version: "3" services:prometheus:#image: prom/prometheus:v2.0.0…

.NET 8 发布!

作者&#xff1a;Gaurav Seth 排版&#xff1a;Alan Wang 请立即下载 .NET 8&#xff01; 我们很高兴地宣布从今天开始 .NET 8 正式发布&#xff0c;它是世界领先的开发平台之一的最新 LTS 版本。.NET 8 提供了数以千计的性能、稳定性和安全性改进&#xff0c;以及平台和工具增…

中学老师求职简历(精选9篇)

以下简历内容以中学老师招聘需求为背景&#xff0c;我们整理并修改了9篇全面、专业且具有参考价值的简历案例&#xff0c;大家可以灵活借鉴&#xff0c;希望能帮助大家在众多候选人中脱颖而出。 中学老师简历下载&#xff08;可在下制作下载&#xff09;&#xff1a;百度幻主简…

抓取微信好友列表信息

本文实现的是一种较为安全、简洁、高效的抓取微信好友信息的方法。 实现工具&#xff1a;微信pc端、影刀RPA 主要流程&#xff1a; 手动—前期准备&#xff0c;电脑登陆微信&#xff0c;打开联系人页&#xff0c;使得联系人分类“A”显现在微信窗口界面 自动—运行程序&#…

JDK21无法导入TimeUnit类

运行环境&#xff1a;windows11、IDEA2023.1.3、JDK21 问题描述&#xff1a;IDEA中无法导入java.util.concurrent.TimeUnit类。 以下截图是问题解决后的截图。有问题的时候未截图&#xff0c;说明一下&#xff0c;有问题的时候TimeUnit类是红色的&#xff0c;无法导入&#x…

vue3中的provide与inject跨层级组件(祖孙)间通信

provide和inject提供依赖注入&#xff0c;功能类似 vue2.x 的provide/inject 实现跨层级组件(祖孙)间通信 子或孙子组件接收到的数据可以用于读取显示&#xff0c;也可以进行修改&#xff0c;同步修改父&#xff08;祖&#xff09;组件的数据。 注意&#xff1a;无论子组件…

python 使用reportlab打造29页图文并茂pdf(全网reportlab最强pdf自动化生成代码)

python 使用reportlab打造29页图文并茂pdf(全网reportlab最强pdf自动化生成代码&#xff09; 这次项目所使用的代码如果同志们可以灵活使用&#xff0c;基本上可以解决百分之九十以上的pdf模板自动化生成。 最近博主&#xff0c;做了一个项目&#xff0c;使用reportlab制作pd…

程序包不存在

idea2020会有一个小bug&#xff0c;在idea的Settings设置中进行下面配置&#xff1a; 然后在maven项目下的pom.xml中加入如下代码&#xff1a; <plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifact…

【Android面试|华为|锁相关】- synchronize(this) 和 synchronize(class)有什么区别

华为面试官问了其中一个问题 Q: synchronize(this) 和 synchronize(class)一样么&#xff1f; 是否可以用synchronize(this) 来锁 A: 当使用 synchronized 加锁 class 时&#xff0c;无论共享一个对象还是创建多个对象&#xff0c;它们用的都是同一把锁&#xff0c;而使用 sync…

【趣味JavaScript】一文让你读懂JavaScript原型对象与原型链的继承,探秘属性的查找机制! 《重置版》

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享博主 &#x1f40b; 希望大家多多支持一下, 我们一起学习和进步&#xff01;&#x1f604; &#x1f3c5; 如果文章对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&a…

Oracle忘记所有密码怎么办

最近遇到一个Oracle的问题&#xff0c;密码要过期了&#xff0c;但是除了用户密码&#xff0c;其他密码都不知道了&#xff0c;修改不了密码怎么办呢&#xff1f; 试了各种方法&#xff0c;最终下面的方式生效了&#xff1a; 首先&#xff0c;使用orapwd生成新的密码文件&…

云计算如何创芯:“逆向工作法”的性感之处

在整个云计算领域&#xff0c;能让芯片规模化的用起来&#xff0c;是决定造芯是否成功的天花板。在拉斯维加斯的亚马逊云科技2023 re:Invent则是完美诠释了这一论调。 亚马逊云科技2023 re:Invent开幕前两个小时&#xff0c;有一场小型的欢迎晚宴&#xff0c;《星期日泰晤士报》…