多线程(基础)

news2025/1/1 22:59:09

文章目录

    • 1. 线程的声明周期
      • 1.1 JDK 中用 Thread.State 枚举表示了线程的几种状态
      • 1.2 线程状态转换图
    • 2. 线程的同步
      • 2.1 Synchronized 线程同步机制
    • 3. 互斥锁
      • 3.1 注意事项和细节
      • 3.2 守护线程 setDaemon()方法
    • 4. 线程的死锁
    • 5. 释放锁
    • 6. 课后练习

1. 线程的声明周期

1.1 JDK 中用 Thread.State 枚举表示了线程的几种状态

image-20230918202710662

1.2 线程状态转换图

image-20230918202750689

package com.xjz.state_;

/**
 * @author xjz_2002
 * @version 1.0
 */
public class ThreadState_ {
    public static void main(String[] args) throws InterruptedException {

        T t = new T();
        System.out.println(t.getName() + "状态" + t.getState());
        t.start();
        while (Thread.State.TERMINATED != t.getState()){
            System.out.println(t.getName() + "状态" + t.getState());
            Thread.sleep(500);
        }

    }
}
class T extends Thread {
    @Override
    public void run() {
        while (true) {
            for (int i = 0; i < 10; i++) {
                System.out.println("hi" + i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            break;
        }
    }
}

2. 线程的同步

2.1 Synchronized 线程同步机制

image-20230918203104104

image-20230918203155198

使用 synchronized 来解决超卖问题

package com.xjz.syn;

/**
 * @author xjz_2002
 * @version 1.0
 * 使用多线程,模拟三个窗口同时售票 100 张 ==》 同步锁 synchronized 防止超卖
 */
public class SellTicket {
    public static void main(String[] args) {

        SellTicket03 sellTicket03 = new SellTicket03();

        new Thread(sellTicket03).start(); //第 1 个线程-窗口
        new Thread(sellTicket03).start(); //第 2 个线程-窗口
        new Thread(sellTicket03).start(); //第 3 个线程-窗口
    }
}

// 实现 Runnable 接口,使用 synchronized 实现线程同步
class SellTicket03 implements Runnable {

    private int ticketNum = 100;//让多个线程共享 ticketNum
    private boolean loop = true;

    public synchronized void sell() { //同步方法,在同一时刻,只能有一个线程来执行 sell方法

        if (ticketNum <= 0) {
            System.out.println("售票结束.");
            loop = false;
            return;
        }

        //休眠 50毫秒,模拟
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("窗口" + Thread.currentThread().getName() + "售出一张票"
                + "剩余票数=" + (--ticketNum));
    }

    @Override
    public void run() {

        while (loop) {
            sell();
        }
    }
}


image-20230918203206829

3. 互斥锁

image-20230918211623420

package com.xjz.syn;

/**
 * @author xjz_2002
 * @version 1.0
 * 使用多线程,模拟三个窗口同时售票 100 张 ==》 同步锁 synchronized 防止超卖
 */
public class SellTicket {
    public static void main(String[] args) {

        SellTicket03 sellTicket03 = new SellTicket03();

        new Thread(sellTicket03).start(); //第 1 个线程-窗口
        new Thread(sellTicket03).start(); //第 2 个线程-窗口
        new Thread(sellTicket03).start(); //第 3 个线程-窗口
    }
}

// 实现 Runnable 接口,使用 synchronized 实现线程同步
class SellTicket03 implements Runnable {

    private int ticketNum = 100;//让多个线程共享 ticketNum
    private boolean loop = true;//控制 run 方法变量
    Object object = new Object();

    //同步方法(静态的)的锁为当前类本身
    //代码解读
    //1. public synchronized static void m1() {} 锁是加在 SellTicket03.class
    //2. 如果在静态方法中,实现一个同步代码块.
    /*
        synchronized (SellTicket03.class) {
            System.out.println("m2");
        }
    */
    public synchronized static void m1(){

    }
    public static void m2() {
        synchronized(SellTicket03.class){
            System.out.println("m2");
        }
    }

    //说明
    //1. public synchronized void sell() {} 就是一个同步方法
    //2. 这时锁在 this 对象
    //3. 也可以在代码块上写 synchronize ,同步代码块, 互斥锁还是在 this 对象
    public /*synchronized*/ void sell() { //同步方法,在同一时刻,只能有一个线程来执行 sell方法

        synchronized (/*this*/ object) {
            if (ticketNum <= 0) {
                System.out.println("售票结束.");
                loop = false;
                return;
            }

            //休眠 50毫秒,模拟
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("窗口" + Thread.currentThread().getName() + "售出一张票"
                    + "剩余票数=" + (--ticketNum));
        }
    }

    @Override
    public void run() {

        while (loop) {
            sell();
        }
    }
}

3.1 注意事项和细节

image-20230918212125524

3.2 守护线程 setDaemon()方法

package com.xjz.method;

/**
 * @author xjz_2002
 * @version 1.0
 * 守护线程
 */
public class ThreadMethod03 {
    public static void main(String[] args) throws InterruptedException {

        MyDaemonThread myDaemonThread = new MyDaemonThread();
        //如果我们希望当 main线程结束后,子线程自动结束
        //,只需将子线程设为 守护线程
        myDaemonThread.setDaemon(true);
        myDaemonThread.start();

        for (int i = 1; i <= 10; i++) {
            System.out.println("宝强在辛苦的工作..");
            Thread.sleep(1000);
        }
    }
}

class MyDaemonThread extends Thread {
    @Override
    public void run() {
        for (; ; ) {//无限循环
            try {
                Thread.sleep(1000);//休眠 1000毫秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("马蓉和宋喆在快乐的聊天,哈哈哈");

        }
    }
}

4. 线程的死锁

多个线程都占用了对方的锁资源,但不肯想让,导致了死锁,在编程里是一定要避免死锁的发生。

  • 应用案例
  • 妈妈:你先完成作业,才让你玩手机
  • 小明:你先让我玩手机,我才完成作业
package com.xjz.syn;

/**
 * @author xjz_2002
 * @version 1.0
 * 模拟死锁线程
 */
public class DeadLock_ {
    public static void main(String[] args) {

        //模拟死锁现象
        DeadLockDemo A = new DeadLockDemo(true);
        A.setName("A 线程");
        DeadLockDemo B = new DeadLockDemo(false);
        B.setName("B 线程");
        A.start();
        B.start();
    }
}

//线程
class DeadLockDemo extends Thread {
    static Object o1 = new Object();//保证多线程,共享一个对象,这里使用 static
    static Object o2 = new Object();
    boolean flag;

    public DeadLockDemo(boolean flag) { //构造器
        this.flag = flag;
    }

    @Override
    public void run() {

        //下面业务逻辑的分析
        //1. 如果 flag 为 T, 线程 A 就会先得到/持有 o1 对象锁, 然后尝试去获取 o2 对象锁
        //2. 如果线程 A 得不到 o2 对象锁,就会 Blocked
        //3. 如果 flag 为 F, 线程 B 就会先得到/持有 o2 对象锁, 然后尝试去获取 o1 对象锁
        //4. 如果线程 B 得不到 o1 对象锁,就会 Blocked
        if (flag) {
            synchronized (o1) {//对象互斥锁,下面就是同步代码
                System.out.println(Thread.currentThread().getName() + "进入1");
                synchronized (o2) {//这里获得 li 对象的监视权
                    System.out.println(Thread.currentThread().getName() + "进入2");
                }
            }
        } else {
            synchronized (o2) {//对象互斥锁,下面就是同步代码
                System.out.println(Thread.currentThread().getName() + "进入3");
                synchronized (o1) {//这里获得 li 对象的监视权
                    System.out.println(Thread.currentThread().getName() + "进入4");
                }
            }
        }
    }
}

5. 释放锁

  • 下面操作释放锁

image-20230918213412654

  • 下面操作不会释放锁

image-20230918213452338

6. 课后练习

image-20230919100120464

package com.xjz.homework;

import java.util.Scanner;

/**
 * @author xjz_2002
 * @version 1.0
 */
public class Homework01 {
    public static void main(String[] args) {
        A a = new A();
        B b = new B(a);
        a.start();
        b.start();
    }
}

/*
    (1) 在 main方法中启动两个线程
    (2) 第 1 个线程循环随机打印 100以内的整数
    (3) 直到第 2 个线程从键盘读取了 “Q" 命令。
 */

class A extends Thread {
    private boolean loop = true;

    public void setLoop(boolean loop) {
        this.loop = loop;
    }

    @Override
    public void run() {
        while (loop) {
            int intNum = (int) (Math.random() * 100) + 1;
            System.out.println("A 线程" + intNum);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("a线程 退出");
    }
}

// 直到第 2 个线程从键盘读取了 “Q" 命令。
class B extends Thread {
    private A a;
    private Scanner scanner = new Scanner(System.in);

    public B(A a) {
        this.a = a;
    }

    @Override
    public void run() {
        while (true) {
            //接收到用户的输入
            System.out.println("请输入你的指令(Q)表示退出:");
            char key = scanner.next().toUpperCase().charAt(0);
            if (key == 'Q'){
                a.setLoop(false);
                break;
            }
        }
        System.out.println("b线程 退出");
    }
}

image-20230919100137611

package com.xjz.homework;

/**
 * @author xjz_2002
 * @version 1.0
 */
public class Homework02 {
    public static void main(String[] args) {

        T t = new T(); //切记,同一个对象创建多个线程
        Thread thread1 = new Thread(t);
        thread1.setName("t1");
        Thread thread2 = new Thread(t);
        thread2.setName("t2");
        thread1.start();
        thread2.start();
    }
}

//1. 有两个用户分别从同一个卡上取钱(总额:10000)
//2. 每次都取 1000,当余额不足时,就不能取款了
//3. 不能出现 超取 线程 =》 线程同步问题
class T implements Runnable {
    private static int balance = 10000;

    @Override
    public void run() {

        while (true) {

            //代码解读
            //1. 这里使用 synchronized 实现了线程同步
            //2. 当多个线程执行到这里时,就会去争夺 this 对象锁
            //3. 哪个线程争夺到(获取) this 对象锁,就执行 synchronized 代码块,执行完后,会释放 this对象锁
            //4. 争夺不到 this对象锁,就 blocked,准备继续争夺
            //5. this 对象锁是非公平锁

            synchronized (this) {
                //判断余额是否够
                if (balance < 1000) {
                    System.out.println("余额不足,无法取款");
                    break;
                }
                //取钱
                balance -= 1000;
                System.out.println(Thread.currentThread().getName() + "取出 1000,剩余" + balance);
            }
            //休眠 500ms
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

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

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

相关文章

四通道信息融合下的齿轮箱故障诊断(Python代码,SVM模型和CNN模型进行对比实验,解压缩即可运行,有详细中文注释)

1.效果运行视频&#xff1a;四通道信息融合下的齿轮箱故障诊断&#xff08;Python代码&#xff0c;SVM模型和CNN模型进行对比实验&#xff09;_哔哩哔哩_bilibili 用到的库&#xff1a; 2.数据集介绍&#xff1a;数据免费下载链接&#xff08;不要积分&#xff09;&#xff1a…

什么是跨站请求伪造(CSRF)攻击?如何防止它?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 什么是跨站请求伪造&#xff08;CSRF&#xff09;攻击&#xff1f;⭐ 如何防止CSRF攻击&#xff1f;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦…

xxl-job 2.2之后版本高版本executor未授权访问漏洞

xxl-job 低版本executor未授权访问 低版本的executor未授权访问漏洞是 POST /run HTTP/1.1 Host: your-ip:9999 Accept-Encoding: gzip, deflate Accept: */* Accept-Language: en User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like G…

26663-2011 大型液压安全联轴器 课堂随笔

声明 本文是学习GB-T 26663-2011 大型液压安全联轴器. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了大型液压安全联轴器的分类、技术要求、试验方法及检验规则等。 本标准适用于联接两同轴线的传动轴系&#xff0c;可起到限制…

基于Linux 系统聊天室登录与注册实现(03)

上一篇我们已经讲了如何搭建一个多线程的服务器模型&#xff0c;可以支持多个客户端同时连接服务器&#xff0c;本篇我们来实现多个客户端&#xff0c;如何实现向服务器注册信息&#xff0c;并实现登录的功能。 数据结构 接着上一篇的实例代码继续增加功能。要实现注册和登录…

(Java)关于easyExcel合并单元格

今天过客遇到一个需要合并单元格的业务&#xff0c;但是之前过客用的一直是easyExcel框架&#xff0c;所以这次也不想去使用其他的框架&#xff0c;今天就跟大家讲讲easyExcel怎么进行单元格的合并。 首先使用easyExcel进行导出的实体类一样是依据之前那样写&#xff0c;之后在…

宠物玩具在欧洲销售CE认证EN71测试标准

CE认证的EN71测试宠物玩具办理&#xff1a; 宠物玩具是用来给宠物玩耍&#xff0c;基于将宠物作为人类伙伴关系而诞生的一种玩具类型&#xff0c;这种玩具的存在就是让人类和自己的宠物真正的互动起来&#xff0c;在情感上面得到更大的交流和互动。 那么宠物玩具出口到欧盟市场…

支付宝电脑网站支付,异步通知

一&#xff1a;异步通知是支付宝回调商户的服务器&#xff0c;所以这个地址需要通过外网访问&#xff0c;在真实项目中都会有对应的服务器&#xff0c;但是在测试中只有使用内网穿透工具 推荐使用NATAPP-内网穿透 基于ngrok的国内高速内网映射工具 配置好内网穿透之后不要忘记…

目标检测如何演变:从区域提议和 Haar 级联到零样本技术

目录 一、说明 二、目标检测路线图 2.1 路线图&#xff08;一般&#xff09; 2.2 路线图&#xff08;更传统的方法&#xff09; 2.3 路线图&#xff08;深度学习方法&#xff09; 2.4 对象检测指标的改进 三、传统检测方法 3.1 维奥拉-琼斯探测器 (2001) 3.2 HOG探测器…

最大内切圆算法计算裂缝宽度

本文这里是对CSDN上另一位博主的代码进行了整理&#xff1a; 基于opencv的裂缝宽度检测算法&#xff08;计算轮廓最大内切圆算法&#xff09; 我觉得这位博主应该是上传了一个代码草稿&#xff0c;我对其进行了重新整理&#xff0c;并添加了详细的注释。 import cv2 import …

产业园区中工业厂房的能源综合配置

安科瑞 崔丽洁 园区工业地产中能源综合配置存在的问题 我国园区工业地产建设已历经近40年的发展, 园区在区域经济发展、产业集聚方面发挥了重要的载体和平台作用, 有力推动了我国社会经济的高质量发展。园区工业地产是国民经济的发展的重要载体, 但同时也是集中的环境污染源。…

大数据Doris(一):Doris概述篇

文章目录 Doris概述篇 一、前言 二、Doris简介

Norms and Inner Products

See https://ai.stanford.edu/~gwthomas/notes/norms-inner-products.pdf

Jenkins 权限管理

关于Role-based Authorization Strategy 使用Jenkins自身的权限管理过于粗糙&#xff0c;无法对单个、一类项目做管理&#xff0c;我们可以使用 Role-based Authorization Strategy插件来管理项目、角色。 首先安装该插件&#xff1a;在Jenkins查看该插件有无安装 在Jenkins-…

C++ 类和对象 (5) 析构函数

用构造函数创建对象后&#xff0c;程序负责跟踪该对象&#xff0c;直到对象过期为止。对象过期时&#xff0c;程序将自动调用一个特殊的成员函数&#xff0c;该函数的名称——析构函数。析构函数完成清理工作&#xff0c;实际上还是很有用的。例如&#xff0c;用new来分配一个构…

八、【漏洞复现】jupyter-notebook 命令执行(CVE-2019-9644)

8.0、基础知识 1、测试功能点 &#xff08;这种情况基本上很难遇到&#xff09; 8.1、漏洞原理 ​Jupyter Notebook是一套用于创建、共享代码和说明性文本文档的开源Web应用程序。 Jupyter Notebook可直接使用命令行执行任意命令。​ 8.2、影响范围 未授权开启终端权限的…

嵌入式Linux应用开发-基础知识-第七章 具体单板的 LED驱动程序

嵌入式Linux应用开发-基础知识-第七章 具体单板的 LED驱动程序 第七章 具体单板的 LED 驱动程序7.1 怎么写 LED 驱动程序&#xff1f;7.2 AM335X的 LED驱动程序7.2.1 原理图 XXXXXX_AM335X开发板结构为&#xff1a;7.2.2 所涉及的寄存器操作7.2.3 写程序7.2.4 配置内核去掉原有…

PyTorch meshgrid 生成网格坐标

torch.meshgrid(*tensors, indexingNone) 使用输入的 1-D 张量创建网格坐标 示例 indexing‘xy’ import torcha torch.arange(3) b torch.arange(3, 6)x, y torch.meshgrid(a, b, indexingxy) print(x , x, sep\n) print(y , y, sep\n)输出: x tensor([[0, 1, 2],[0, …

麒麟信安组织开展国产操作系统技术赋能专题培训

近日&#xff0c;为学习国产操作系统基本概念、使用与运维知识&#xff0c;应对用户单位内部信息系统国产化需求&#xff0c;来自国营洛阳丹城无线电厂的运维工程师们走进麒麟信安&#xff0c;进行了为期一周的操作系统课程学习。 针对客户此次培训需求&#xff0c;结合学员实…

uni-app:canvas-图形实现1

效果 代码 <template><view><!-- 创建了一个宽度为300像素&#xff0c;高度为200像素的canvas元素。canvas-id属性被设置为"firstCanvas"&#xff0c;可以用来在JavaScript中获取该canvas元素的上下文对象。 --><canvas style"width:200p…