当前位置: 首页 > news >正文

线程(Thread)的使用方法和锁(同步代码块,lock锁)的问题

多线程:
        进程:
            正在运行的程序,是系统进行资源分配和调用的独立单位。
            每一个进程都有它自己的内存空间和系统资源。
            理解:一个正在运行的软件
        线程:
            是进程中的单个顺序控制流,是一条执行路径
            一个进程如果只有一条执行路径,则称为单线程程序。
            一个进程如果有多条执行路径,则称为多线程程序。
            举例:阿里云盘(进程)中多个同时进行的任务,每一个任务可以看作一个线程

    1、如何创建一个线程对象呢?
        a. 自定义线程类继承Thread类,重写run方法
        b. 自定义线程类实现Runnable接口,实现run方法

    2、如何启动一个线程呢?
        调用start()方法启动

    Thread无参构造方法

     Thread() 分配一个新的 Thread对象。


    注意:
        1、启动一个线程的时候,若直接调用run方法,仅仅是普通的对象调用方法,按照自上而下的顺序执行,底层不会额外的创建一个线程再执行
        2、从执行的结果上来看,java线程之间是抢占式执行的,谁先抢到cpu执行权谁就先执行
        3、每次运行的结果顺序不可预测的,完全随机的
        4、每个线程都有优先权。 具有较高优先级的线程优先于优先级较低的线程执行。只是优先级高的先执行的概率大一点,并不代表一定先执行,完全是随机。

    Thread类中的成员方法:


        1、public final String getName()  获取线程对象的名字
        2、设置线程对象名字的方式:
            a. 通过父类的有参构造方法,在创建线程对象的时候设置名字
            b. 线程对象调用setName(String name)方法,给线程对象设置名字
        3、获取线程的等级
            getPriority() 默认优先级都是5
        4、设置线程优先级,setPriority(int i),在启动之前设置  [1,10]
            注意不是优先级高的一定先执行,只是可能性变高了。

Thread中sleep()、stop()、join()、yield()、setDaemon()、wait(),notify()的方法使用:
sleep()的使用:线程休眠

    线程控制:休眠线程
    当线程处于休眠状态的时候,该线程就没有cpu执行权了,若这时还有其他的线程,会被抢走cpu执行权。

代码如下:

class SleepThread extends Thread {@Overridepublic void run() {System.out.println(getName() + " 睡着了。。。。");try {Thread.sleep(5000); // 在哪个方法中调用,就是调用该方法的线程对象进行休眠} catch (InterruptedException e) {e.printStackTrace();}System.out.println(getName()+" 睡醒了。。。。");}
}public class ThreadSleepDemo1 {public static void main(String[] args) {SleepThread t1 = new SleepThread();t1.setName("光头强");t1.start();}
}

stop()的使用:线程中断

class StopThread extends Thread {@Overridepublic void run() {System.out.println(getName() + " 睡着了。。。。");try {Thread.sleep(5000); // 在哪个方法中调用,就是调用该方法的线程对象进行休眠} catch (InterruptedException e) {e.printStackTrace();}System.out.println(getName()+" 睡醒了。。。。");}
}public class ThreadStopDemo1 {public static void main(String[] args) {StopThread t1 = new StopThread();t1.setName("熊大");t1.start();try {Thread.sleep(2000);
//            t1.stop();t1.interrupt();} catch (InterruptedException e) {e.printStackTrace();}}
}

join()的使用:线程加入
class JoinThread extends Thread {@Overridepublic void run() {for (int i = 1; i <= 10; i++) {System.out.println(getName() + " - " + i);}}
}public class ThreadJoinDemo1 {public static void main(String[] args) {JoinThread t1 = new JoinThread();JoinThread t2 = new JoinThread();JoinThread t3 = new JoinThread();t1.setName("光头强");t2.setName("熊大");t3.setName("熊二");t1.start();try {t1.join(); // 其他线程等待该线程执行结束,其他线程之间会进行抢占式执行} catch (InterruptedException e) {e.printStackTrace();}t2.start();t3.start();}
}

yield()的使用:线程礼让

只是让结果看起来更加均匀一些,并不是我们日常生活中理解的完全谦让

 礼让线程yield()只是为了运行结果看起来均匀一些class YieldThread extends Thread{@Overridepublic void run() {for(int i=1;i<200;i++){System.out.println(getName()+" - "+i);Thread.yield();}}
}public class ThreadYieldDemo1 {public static void main(String[] args) {YieldThread t1 = new YieldThread();YieldThread t2 = new YieldThread();t1.setName("民哥");t2.setName("原神哥");t1.start();t2.start();}
}
setDaemon()后台线程:

        用户线程
        守护线程
    在启动之前,设置一下若一个进程中没有用户线程,守护线程也没有必要存在。

class DaemonThread extends Thread {@Overridepublic void run() {for (int i = 1; i <= 200; i++) {System.out.println(getName() + " - " + i);}}
}public class ThreadDaemonDemo1 {public static void main(String[] args) {DaemonThread t1 = new DaemonThread();DaemonThread t2 = new DaemonThread();DaemonThread t3 = new DaemonThread();t1.setName("刘备");t2.setName("关羽");t3.setName("张飞");t2.setDaemon(true);t3.setDaemon(true);t1.start();t2.start();t3.start();}
}
wait()和notify()的使用:可用于生产者和消费者模型中,wait()就是等待,等待某个程序的完成后,再进行解锁notify(),再让其他程序运行,wait()等待期间,属于程序阻塞

 使用Runnable的方式实现:售票问题(SellTickets)

 为了模拟更加真实的售票情况,我们加入延迟
    问题:
        我们加入了延迟之后,发现
        a. 有重复售卖同一张票的情况(原因1)
        b. 还出现了一个不该出现的票数据,比如第0张票,第-1张票(原因2)
    原因:
        1. cpu小小的时间片,足以让程序执行很多次
        2. 线程的执行具有随机性,且是抢占式执行的

 现象:线程不安全的现象
        如何判断一个程序是否存在线程不安全的现象呢?
        三要素(同时满足):
            1、是否存在多线程环境?
            2、是否存在共享数据?
            3、是否存在多条语句操作着共享数据?
    如何解决线程不安全的现象?
        1、同步代码块
        2、lock锁

    解决方案1:加入同步代码块
        synchronized(对象){
            操作共享数据的代码
        }
      这里的对象,可以是任意一个new出来的对象,但是要保证多个线程之间是同一个对象。

   synchronized的使用
        1、同步代码块 - 锁对象 - 任意一个对象,前提是多个线程对象共享一个
        2、同步方法 - 锁对象 - this
        3、同静态方法 - 锁对象 - 当前类的class文件对象

    解决方案2:lock锁,利用ReentrantLock类创建锁对象,要求多个线程对象共享一个
        不需要考虑锁对象是谁了。
 
同步代码块1:锁任意对象--Object
class Window implements Runnable{private static int tickets = 100;private Object object = new Object();@Overridepublic void run() {while (true){synchronized (object){if(tickets>0){try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+" 正在出售第 "+(tickets--)+" 张票......");}}}}
}public class SellTicketDemo1 {public static void main(String[] args) {Window window = new Window();Thread w1 = new Thread(window,"窗口1");Thread w2 = new Thread(window,"窗口2");Thread w3 = new Thread(window,"窗口3");w1.start();w2.start();w3.start();}
}
同步代码块2:锁对象--this
class Window implements Runnable {private static int tickets = 100;
//    private Object object = new Object();private int i = 0;@Overridepublic void run() {while (true) {if (i % 2 == 0) {synchronized (this) {if (tickets > 0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票......");}}} else {sellTicket();}i++;}}//同步方法,将synchronized在方法定义上出现
//    public synchronized void sellTicket() {
//        if (tickets > 0) {
//            try {
//                Thread.sleep(50);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票......");
//        }
//    }public static synchronized void sellTicket() {if (tickets > 0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票......");}}
}public class SellTicketDemo1 {public static void main(String[] args) {Window window = new Window();Thread w1 = new Thread(window, "窗口1");Thread w2 = new Thread(window, "窗口2");Thread w3 = new Thread(window, "窗口3");w1.start();w2.start();w3.start();}
}
同步代码块3:锁对象--当前类的class文件对象
class Window implements Runnable {private static int tickets = 100;
//    private Object object = new Object();private int i = 0;@Overridepublic void run() {while (true) {if (i % 2 == 0) {synchronized (Window.class) {if (tickets > 0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票......");}}} else {sellTicket();}i++;}}//同步方法,将synchronized在方法定义上出现
//    public synchronized void sellTicket() {
//        if (tickets > 0) {
//            try {
//                Thread.sleep(50);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票......");
//        }
//    }public static synchronized void sellTicket() {if (tickets > 0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票......");}}
}public class SellTicketDemo1 {public static void main(String[] args) {Window window = new Window();Thread w1 = new Thread(window, "窗口1");Thread w2 = new Thread(window, "窗口2");Thread w3 = new Thread(window, "窗口3");w1.start();w2.start();w3.start();}
}
lock锁:不用考虑锁对象
class Window implements Runnable {private static int tickets = 100;//    private Object object = new Object();private ReentrantLock lock = new ReentrantLock();@Overridepublic void run() {while (true) {lock.lock(); // 加锁if (tickets > 0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票......");}lock.unlock(); // 释放锁}}
}public class SellTicketDemo1 {public static void main(String[] args) {Window window = new Window();Thread w1 = new Thread(window, "窗口1");Thread w2 = new Thread(window, "窗口2");Thread w3 = new Thread(window, "窗口3");w1.start();w2.start();w3.start();}
}
 死锁情况:

分两个类:Locks对象类,测试类,  死锁的问题:线程之间存在相互等待的现象

Locks对象类:


import java.util.concurrent.locks.ReentrantLock;public class Locks {private Locks(){}public static final ReentrantLock lock1 = new ReentrantLock();public static final ReentrantLock lock2 = new ReentrantLock();
}

测试类:

class Person extends Thread{private boolean flag;public Person(boolean flag) {this.flag = flag;}@Overridepublic void run() {if(flag){synchronized (Locks.lock1){System.out.println("if lock1");// p1synchronized (Locks.lock2){System.out.println("if lock2");}}}else {synchronized (Locks.lock2){System.out.println("else lock2");// p2synchronized (Locks.lock1){System.out.println("else lock1");}}}}
}public class DieLockDemo {public static void main(String[] args) {Person p1 = new Person(true);Person p2 = new Person(false);p1.start();p2.start();}
}

相关文章:

线程(Thread)的使用方法和锁(同步代码块,lock锁)的问题

多线程&#xff1a; 进程&#xff1a; 正在运行的程序&#xff0c;是系统进行资源分配和调用的独立单位。 每一个进程都有它自己的内存空间和系统资源。 理解&#xff1a;一个正在运行的软件 线程&#xff1a; …...

Java 反射机制

Java 反射&#xff08;Reflection&#xff09;是 Java 语言提供的一种在运行时动态获取类信息、创建对象、调用方法、访问属性等功能的机制。它允许程序在运行时对类进行检查、修改和调用&#xff0c;而不需要在编译时就知道类的具体信息。 一、反射的主要类和方法 Class类&…...

详解MBR分区结构以及GPT分区结构

学习笔记: GUID&#xff08;GPT&#xff09;分区表详解_gpt分区表-CSDN博客 详解MBR分区结构以及GPT分区结构-CSDN博客 其中U盘作为移动存储设备&#xff0c;可不具备上述分区&#xff0c;也可识别...

jvm 调优篇

一 jvm调优篇 1.1 查看新生代和老年代的比例 输入命令&#xff1a; jinfo -flag NewRatio 17480 1.2 查看新生代&#xff0c;survivor和Eden区比例 1.3 查看jvm调优参数 二 调优参数 2.1 oom异常 通过visual vm查看 2.java dump 大对象 2.2 mat工具进行分析 栈的信息...

Spring AOP应用指南:概念、通知与表达式分析

目录 一.AOP的基础概念 二.Spring AOP的应用场景 三.Spring AOP的核心概念 ▐ 切点(Pointcut) ▐ 连接点(Join Point) ▐ 通知(Advice) ▐ 切面(Aspect) 通知类型 四.PointCut与Order 切面优先级 五.切点表达式 execution(...)表达式 annotation表达式 一.AOP的基…...

汽车的UDS诊断01

UDS(Unified Diagnostic Services):ISO14229中定义了汽车通用诊断协议;ISO15765规定了帧的格式; 1)UDS中的四种帧 UDS中的四种帧:单帧、首帧、流空帧、连续帧 图1 …...

MySQL——单表查询(二)按条件查询(6)DISTINCT 关键字作用于多个字段

DISTINCT 关键字可以作用于多个字段&#xff0c;其语法格式如下所示&#xff1a; SELECT DISTINCT 字段名 1,字段名 2,… FROM 表名; 在上面的语法格式中&#xff0c;只有 DISTINCT 关键字后指定的多个字段值都相同&#xff0c;才会裱认作是重复记录。 例如&#xff0…...

python从入门到精通:数据容器

数据容器介绍 一种可以容纳多份数据的数据类型&#xff0c;容纳的每一份数据称之为一个元素&#xff0c;可以是任意类型的数据&#xff0c;如字符串、数字、布尔等。 数据容器根据特点的不同&#xff0c;如&#xff1a; 是否支持重复元素 是否可以修改 是否有序&#xff0…...

Java 中都有哪些引用类型?

Java 中都有哪些引用类型&#xff1f; 强引用 在 Java 中最常见的就是强引用&#xff0c;把一个对象赋给一个引用变量&#xff0c;这个引用变量就是一个强引用。当一个对象被强引用变量引用时&#xff0c;它处于可达状态&#xff0c;它是不可能被垃圾回收机制回收的。因此强引…...

使用 Dify 和 AI 大模型理解视频内容:Qwen 2 VL 72B

接下来的几篇相关的文章&#xff0c;聊聊使用 Dify 和 AI 大模型理解视频内容。 本篇作为第一篇内容&#xff0c;以昨天出圈的“黑神话悟空制作人采访视频”为例&#xff0c;先来聊聊经常被国外厂商拿来对比的国产模型&#xff1a;千问系列&#xff0c;以及它的内测版。 写在…...

mybatisplus 通过xml 定义接口

在 MyBatis-Plus 中&#xff0c;虽然它极大地简化了 CRUD 操作&#xff0c;提供了许多注解方式&#xff08;如 Select、Insert、Update、Delete&#xff09;来直接在 Mapper 接口上定义 SQL 语句&#xff0c;但 MyBatis-Plus 仍然支持传统的 MyBatis 风格的 XML 配置方式来定义…...

上周稼先社区的活动

参天是什么&#xff1f; 最近”参天”很火&#xff0c;不仅MySQL社区&#xff0c;听说Monty最近也跟他们搞了很多活动。其实说起华为的数据库&#xff0c;只有从事数据库行业的人才知道高斯&#xff0c;其他很多人不知道。但是即使从事数据库相关的人&#xff0c;对另外一个产…...

day_45

115. 不同的子序列 class Solution:def numDistinct(self, s: str, t: str) -> int:dp [[0] * (len(t) 1) for _ in range(len(s) 1)]for i in range(len(s)):dp[i][0] 1for j in range(1, len(t)):dp[0][j] 0for i in range(1, len(s) 1):for j in range(1, len(t) …...

SQL 时间盲注 (injection 第十六关)

简介 SQL注入&#xff08;SQL Injection&#xff09;是一种常见的网络攻击方式&#xff0c;通过向SQL查询中插入恶意的SQL代码&#xff0c;攻击者可以操控数据库&#xff0c;SQL注入是一种代码注入攻击&#xff0c;其中攻击者将恶意的SQL代码插入到应用程序的输入字段中&#x…...

nginx核心配置示例

1.核心配置示例 基于不同的IP、不同的端口以及不用得域名实现不同的虚拟主机&#xff0c;依赖于核心模块 ngx_http_core_module实现。 1.新建一个 PC web 站点 # 访问测试 [rootnode100 ~]# curl www.root.org # 注意在访问主机中设解析 2.root 与 alias root &#xff1a;指…...

【面向对象】04面向对象三大特征之——继承

文章目录 一、super1.构造方法2.属性3.方法 二、规则三、继承权限 继承 继承是Java中实现代码重用的重要手段之一。使用继承&#xff0c;可以减少代码量&#xff0c;方便修改代码。Java中只支持单根继承&#xff0c;即一个类只能有一个直接父类。 继承使用关键字extends&#…...

计算机毕业设计Python+Flask弹幕情感分析 B站视频数据可视化 B站爬虫 机器学习 深度学习 人工智能 NLP文本分类 数据可视化 大数据毕业设计

### 开题报告&#xff1a;基于Python和Flask的弹幕情感分析系统 #### 一、研究背景 弹幕&#xff08;Danmaku&#xff09;是一种实时在视频播放过程中显示的评论或弹幕&#xff0c;起初源于日本&#xff0c;但在中国的二次元文化和直播平台中得到了广泛应用。弹幕作为一种独特…...

用基础项目来理解spring的作用

简介 spring官方的解释过于专业化&#xff0c;初学者可能比较难懂&#xff0c;接下来我将通过一个最基础的Java项目来尽可能的展示spring中的作用及spring的底层是如何来实现的。 项目结构 该项目是一个简单的JavaSE项目&#xff0c;没有maven或者tomcat等其他。只在控制台进…...

Json-复杂泛型解析工具类

为了处理复杂的 JSON 泛型解析任务,你可以创建一个通用的工具类来封装这些操作。这里分别 针对 Jackson 和 Fastjson 提供两个工具类的例子。 1. Jackson 的 JSON 泛型解析工具类 import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackso…...

CLIP-VIT-L + Qwen 多模态学习笔记 -3

多模态学习笔记 - 3 参考repo:WatchTower-Liu/VLM-learning; url: VLLM-BASE 吐槽 今天接着昨天的源码继续看&#xff0c;黑神话&#xff1a;悟空正好今天发售&#xff0c;希望广大coder能玩的开心~ 学习心得 前情提要 详情请看多模态学习笔记 - 2 上次我们讲到利用view(…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

Docker 运行 Kafka 带 SASL 认证教程

Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明&#xff1a;server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)

上一章用到了V2 的概念&#xff0c;其实 Fiori当中还有 V4&#xff0c;咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务)&#xff0c;代理中间件&#xff08;ui5-middleware-simpleproxy&#xff09;-CSDN博客…...

系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文通过代码驱动的方式&#xff0c;系统讲解PyTorch核心概念和实战技巧&#xff0c;涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...

Monorepo架构: Nx Cloud 扩展能力与缓存加速

借助 Nx Cloud 实现项目协同与加速构建 1 &#xff09; 缓存工作原理分析 在了解了本地缓存和远程缓存之后&#xff0c;我们来探究缓存是如何工作的。以计算文件的哈希串为例&#xff0c;若后续运行任务时文件哈希串未变&#xff0c;系统会直接使用对应的输出和制品文件。 2 …...