十七、多线程

一、目标

  • 理解线程的概念
  • 掌握线程的创建和启动
  • 了解线程的状态
  • 掌握线程调度的常用方法
  • 掌握线程的同步
  • 理解线程安全的类型

二、进程、线程、多线程的理解

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

线程:CPU调度和分派的基本单位、进程中执行运算的最小单位,可完成一个独立的顺序控制流程

进程由多个线程组成

什么是多线程

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

多线程好处

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

三、主线程

  • 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中创建线程的两种方式

  •            继承java.lang.Thread类
public class MyThread extends Thread{
    @Override
    public void run() {
        //循环输出1-20之间的所有的整数
        for (int i = 1; i < 21; i++) {
            System.out.println(Thread.currentThread().getName()+"正在运行"+i+"次");
        }

    }
}

public class Test {
    public static void main(String[] args) {
        for (int i = 1; i < 21; i++) {
            System.out.println(Thread.currentThread().getName()+"这是循环的第"+i);
        }
        //创建自定义线程类的对象
        MyThread myThread=new MyThread();
        MyThread myThread1=new MyThread();

        //修改线程名
        myThread1.setName("线程B");
        myThread.setName("线程A");


        //启动线程
        //通过线程直接调用run()方法,由main执行
      /*  myThread.run();*/
        //通过线程调用start()方法来启动线程,是由子线程来执行myThread.start();

        myThread.start();
        myThread1.start();
    }
}
  •            实现java.lang.Runnable接口
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        //循环输出1-20之间所有的整数
        for (int i = 1; i < 21; i++) {
            System.out.println(Thread.currentThread().getName()+"正在运行"+i+"次");
        }

    }
}


public class Test {
    public static void main(String[] args) throws InterruptedException {
        MyRunnable myRunnable=new MyRunnable();
        //启动线程
        /*myRunnable.run();*/
        //myRunnable类中没有start()方法,他实现的接口也没有start()方法,因为start()方法是Thread中的
        Thread thread1=new Thread(myRunnable,"吴子涵");
        Thread thread2=new Thread(myRunnable,"吴狗");
       /* //修改线程名字
        thread1.setName("吴子涵");
        thread2.setName("吴狗");*/

        //修改线程优先级
      /*  thread1.setPriority(1);
        thread2.setPriority(10);*/
        thread1.start();
        thread2.start();
    }
}

使用线程的步骤

  •   定义线程
  •   创建线程对象
  •   启动线程
  •   终止线程

以上两种创建方式的区别

  • 继承Thread类
  • 编写简单,可直接操作线程

适用于单继承

  • 实现Runnable接口
  • 避免单继承局限性 便于共享资源

五、线程的状态

六、线程的调度(各种方法的使用)

1、优先级:void setPriority(int  newPriority)

 //设置优先级
        thread1.setPriority(1);
        thread2.setPriority(10);

wait() 方法需要在一个同步块或同步方法中被调用,这是因为 wait() 方法会释放对象锁,使得其他线程可以进入同步块或同步方法,获取该对象的锁并执行,如果不在同步块或同步方法中调用 wait(),将会抛出 IllegalMonitorStateException 异常。当一个线程调用了对象的 wait() 方法后,该线程将会进入等待状态,直到其他线程调用了该对象的 notify() 或 notifyAll() 方法,在这期间,该线程会释放对象锁,使得其他线程可以获取该对象的锁并执行。

2、休眠:static void sleep(long millis)

            将一个线程休眠,停止运行,cpu可以被其他线程占用

public class SleepDemo01 {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("线程开始执行");
        //线程休眠5秒
        Thread.sleep(5000);
        System.out.println("线程结束执行");
    }
}

3、强制运行:void join()

            强制运行一个线程,等待这个线程运行完成之后,其他线程才能去抢占cpu

public class Test {
    public static void main(String[] args) throws InterruptedException {
        //创建线程
        MyRunnable myRunnable=new MyRunnable();
        Thread thread=new Thread(myRunnable);
//        thread.setPriority(10);
        thread.start();

        for (int i = 10; i < 100; i+=10) {
            System.out.println(Thread.currentThread().getName()+"运行的次数是"+i+"次");
//        强制执行线程 会暂停当前正在运行的线程main 当强制执行完了,暂停执行的当前线程会继续执行
            if(i==50){
                thread.join();
            }

        }

    }
}

4、礼让:static void yield()

            当一个线程抢到cpu资源之后不运行,主动退出,然后再次和其他线程去争抢cpu资源

  

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 1; i <10 ; i++) {
            System.out.println(Thread.currentThread().getName()+"正在运行第"+i+"次");
            if(i==3){
                System.out.print("线程礼让");
                Thread.yield();
            }
        }
    }
}

七、多线程共享数据解决方法(同步方法)

使用synchronized修饰的方法控制对类成员变量的访问

  •      访问修饰符 synchronized 返回类型 方法名(参数列表){……}
  •      synchronized 访问修饰符 返回类型 方法名(参数列表){……}
public class Site implements Runnable {
    private int num = 10;
    //    购买到的是第几张票
    private int count = 0;


    @Override
    public void run() {
      while (true){
          if (!sale()){
              break;
          }
      }
    }

    //定义一个同步方法,实现卖票
    public synchronized boolean sale() {
        if (num <= 0) {
            return false;
        }
        num--;
        count++;
//    模拟网络延迟
       /* try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }*/
//    输出一下卖票信息,看一下是哪个线程的用户购买了票
        System.out.println(Thread.currentThread().getName() + "购买了的第" + count + "张票剩余" + num + "张票");

        return true;
    }

}

使用synchronized关键字修饰的代码块

public void run() {
    while (true) {
        synchronized (this) {   //同步代码块
        // 省略修改数据的代码......
       // 省略显示信息的代码......
}}}
public class Site implements Runnable {
    //   定义两个属性用来统计票的数目和买到的是第几张票
//   票剩余的数量
    private int num = 10;
    //    购买到的是第几张票
    private int count = 0;


    @Override
    public void run() {
        while (true) {
//    票卖完了就可以结束这个循环
            synchronized (this) {
                if (num <= 0) {
                    break;
                }
                num--;
                count++;
//    模拟网络延迟
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
//    输出一下卖票信息,看一下是哪个线程的用户购买了票
                System.out.println(Thread.currentThread().getName() + "购买了的第" + count + "张票剩余" + num + "张票");
            }
        }
    }
}

八、线程安全的类型

 

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

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

相关文章

2023数据要素市场十大关键词

2023数据要素市场十大关键词 导读 2023年即将过去。一年之前&#xff0c;《中共中央国务院关于构建数据基础制度更好发挥数据要素作用的意见》&#xff08;简称“数据二十条”&#xff09;正式对外发布&#xff0c;为数据要素市场的建设举旗定向。 图片 2023年是“数据二十条…

抖店开通后的这些基础搭建,你了解吗?今天一文详解!

大家好&#xff0c;我是电商小布。 很多小伙伴在我们店铺开通后&#xff0c;接下来就会进行选品上架等工作。 但其实&#xff0c;在店铺刚开通时&#xff0c;小店的基础设置是并不完善的。 比如说&#xff1a;平台默认店铺是全地区包邮的。 想要让小店顺利运转&#xff0c;…

徐晓艺被波兰前总统布罗尼斯瓦夫·科莫罗夫斯基接见

2024年1月19日,科莫罗夫斯基阁下总统俱乐部全球主席总统有话说共同主席波兰第五任总统布罗尼斯瓦夫科莫罗夫斯基 Former President of Poland莅临北京丰台宴 科莫罗夫斯基总统阁下一生充满传奇,他的外交成就也颇为杰出,其中一项就是中波关系。他说:“我作为总统在2011年对华访…

vue3 toRefs之后的变量修改方法

上效果 修改值需要带上解构之前的对象名obj&#xff0c; changeName:()>{ // toRefs 解决后变量修改值方法&#xff1a; 解构前变量.字段新值 obj.name FEIFEI; } } 案例源码 <!DOCTYPE html> <html> <head><me…

【Azure 架构师学习笔记】- Azure Databricks (10) -- UC 使用

本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Databricks】系列。 接上文 【Azure 架构师学习笔记】- Azure Databricks (9) – UC权限 在前面的文章&#xff1a;【Azure 架构师学习笔记】- Azure Databricks (6) - 配置Unity Catalog中演示了如何配置一个UC。 本文…

【Vuforia+Unity】AR04-地面、桌面平面识别功能

不论你是否曾有过相关经验&#xff0c;只要跟随本文的步骤&#xff0c;你就可以成功地创建你自己的AR应用。 官方教程Ground Plane in Unity | Vuforia Library 这个功能很棒&#xff0c;但是要求也很不友好&#xff0c;只能支持部分移动设备&#xff0c;具体清单如下&#xf…

书生·浦语大模型实战营第六节课作业

基础作业 python run.py --datasets ceval_gen --hf-path /root/model/Shanghai_AI_Laboratory/internlm2-chat-7b/ --tokenizer-path /root/model/Shanghai_AI_Laboratory/internlm2-chat-7b/ --tokenizer-kwargs padding_sideleft truncationleft trust_remote_codeTrue --m…

栽花-第15届蓝桥第4次STEMA测评Scratch真题精选

[导读]&#xff1a;超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成&#xff0c;后续会不定期解读蓝桥杯真题&#xff0c;这是Scratch蓝桥杯真题解析第169讲。 第15届蓝桥杯第4次STEMA测评已于2024年1月28日落下帷幕&#xff0c;编程题一共有6题&#xff0c;分别如下&a…

HarmonyOS—添加/删除Module

Module是应用/服务的基本功能单元&#xff0c;包含了源代码、资源文件、第三方库及应用/服务配置文件&#xff0c;每一个Module都可以独立进行编译和运行。一个HarmonyOS应用/服务通常会包含一个或多个Module&#xff0c;因此&#xff0c;可以在工程中创建多个Module&#xff0…

什么是web组态?

一、web组态的定义和背景 在深入探讨之前&#xff0c;我们先回顾一下“组态”的定义。在工业自动化领域&#xff0c;组态软件是用于创建监控和数据采集&#xff08;SCADA&#xff09;系统的工具&#xff0c;它允许工程师构建图形界面&#xff0c;实现与各种设备和机器的数据交互…

性能全面提升!探索ONLYOFFICE最新8.0版:更快速、更强大,PDF表单编辑轻松搞定!

文章目录 PDF表单功能表单模板 屏幕朗读器功能EXCEL新增功能单变量求解图表向导数字排序 PPT 新增功能新增语言区域设置和优化插件界面 ONLYOFFICE 是由 Ascensio System SIA 推出的一款功能强大的办公套件&#xff0c;其中提供了适用于文本文档、表格以及演示文稿的在线编辑软…

通过盲注脚本复习sqllabs第46关order by 注入

在MySQL支持使用ORDER BY语句对查询结果集进行排序处理&#xff0c;使用ORDER BY语句不仅支持对单列数据的排序&#xff0c;还支持对数据表中多列数据的排序。语法格式如下 select * from 表名 order by 列名(或者数字) asc&#xff1b;升序(默认升序) select * from 表名 or…

win10系统secoclient连接服务器时,报错与对方建立连接超时,配置错误或网络故障

故障原因 secoclient连接时出现超时的故障&#xff0c;之前还是正常的&#xff0c;可能与最近的系统更新有关 解决方案 找到设备管理 找到网络适配器下的SVN adapter V1.0 禁用该适配器 进入C:\Windows\System32\drivers 找到SVNDrv.sys 把这个文件删除或者重命名一下…

解决docker中运行的jar包连不上前端程序

目录 检查端口映射 查看容器的 IP 地址 检查容器网络设置 防火墙和网络策略 前端程序配置 跨域资源共享 (CORS) 日志查看 连接问题通常涉及到网络配置和端口映射。确保你在 Docker 中运行的 JAR 包可以被前端程序访问&#xff0c;可以采取以下步骤来解决问题&#xff1a…

信钰证券|A股IPO失意后转道南下,内地企业成港股上市“主力军”

内地企业已经成为赴港上市的主力。 Wind数据闪现&#xff0c;本年以来到2月21日&#xff0c;在港股初度聆讯的19家公司中&#xff0c;作业地址在内地的有18家&#xff0c;只要一家作业地址在我国香港。此外&#xff0c;本年在港股上市的5家企业&#xff0c;首要作业地址也均在…

【计组】计算机体系结构

1.CPU的组成 1.1 运算器 算术逻辑单元&#xff08;ALU&#xff09;&#xff1a;逻辑运算累加寄存器&#xff08;AC&#xff09;&#xff1a;存储算数运算结果&#xff08;包括中间结果&#xff09;数据缓冲寄存器&#xff08;DR&#xff09;&#xff1a;临时存储从内存中读取…

星河做市基金会全球DAO社区启动,为数字货币市场注入新活力

2024年的数字货币市场即将迎来一次重要的历史性时刻 — 比特币减半&#xff0c;这四年一次的事件将成为全球数字资产市场的焦点&#xff0c;预示着新一轮的牛市浪潮即将到来。在这个关键时刻&#xff0c;星河做市基金会展现出其作为区块链行业领先市值管理公司的独特魅力。 GA…

JVM虚拟机结构

虚拟机结构图 从图中看出&#xff1a; JVM虚拟机主要有三大部分组成&#xff1a; 1. 类加载器 2. JVM运行时内存 3. 执行引擎 一、类加载器 类加载器主要用来加载字节码文件&#xff08;.class&#xff09;到内存中 二、内存结构 如图&#xff1a;可将内存分为两大部分&…

【MATLAB】mlptdenoise信号分解+FFT傅里叶频谱变换组合算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~ 展示出图效果 1 mlptdenoise分解算法 MLPT denoise&#xff08;Maximum Likelihood Parameter-Tuned Denoise&#xff09;是一种基于小波变换的信号分解算法&#xff0c;它可以将信号分解为多个具有不同频率特性的小波分…

Kotlin基础 7

1.apply函数详解 1.1. DSL /*** 为什么要传入扩展函数(泛型),而不是一个普通的匿名函数* T.()->Unit* 扩展函数里自带了接收者对象的this隐式调用* 为什么是泛型的扩展函数?* 因为是由this 隐式调用 this 类型就是泛型类型&#xff0c; 相当于this的扩展函数&#xff0c;…