多线程-线程状态和线程安全(加锁-synchronized 关键字)

目录

1.线程状态

 示例:

1.1线程状态和状态转移的意义

2.线程安全

2.1观察线程不安全

2.2线程不安全的原因

3.synchronized 关键字 - 监视器锁 monitor lock

3.1synchronized 的特性

1. 互斥

2.可重⼊

 应用示例:

3.2synchronized 使⽤⽰例  

1. 修饰代码块: 明确指定锁哪个对象.

2.直接修饰普通⽅法: 锁的 SynchronizedDemo 对象

3.修饰静态⽅法: 锁的 SynchronizedDemo 类的对象


1.线程状态

      在Java中,线程有几种不同的状态,可以通过Thread类的getState()方法获取线程的当前状态。

      线程的状态是⼀个枚举类型 Thread.State
public class ThreadState {public static void main(String[] args) {for (Thread.State state : Thread.State.values()) {System.out.println(state);}}
}
  1. NEW(新建):新创建的线程尚未启动。
  2. RUNNABLE(可运行):正在Java虚拟机中执行的线程,可能正在执行,也可能正在等待CPU时间片。
  3. BLOCKED(阻塞):被阻塞并等待监视器锁定的线程。当线程试图进入一个同步代码块,而该块已经被其他线程持有时,该线程将进入阻塞状态。
  4. WAITING(等待):无限期等待另一个线程执行特定操作的线程。线程可以通过调用Object类的wait()方法、Thread类的join()方法或LockSupport类的park()方法进入等待状态。
  5. TIMED_WAITING(计时等待):在等待一段时间后自动恢复运行的线程。线程可以通过调用Thread类的sleep()方法、Object类的wait方法、Thread类的join方法进入计时等待状态。
  6. TERMINATED(终止):已经执行完毕的线程,不再运行。

 示例:

我们用getState()来获取线程的状态。

package 多线程;public class ThreadDemo13 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{for (int i = 0; i < 5; i++) {System.out.println("线程运行中");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});//启动之前状态是new状态System.out.println(t.getState());t.start();System.out.println(t.getState());t.join();System.out.println(t.getState());System.out.println("t线程结束");}
}

       我们查看结果一开始线程的状态是NEW,当我们t.start后线程的状态变成了RUNNABLE,之后线程开始运行。我们使用t.join()提前结束线程。线程状态改变成了TERMINTED。

 

1.1线程状态和状态转移的意义

 

2.线程安全

        线程安全是指在多线程环境下,多个线程同时访问共享资源时,不会出现数据不一致、竞态条件和死锁等问题。在并发编程中,如果多个线程同时访问共享的可变数据,可能会导致数据不一致的情况。例如,一个线程在读取一个共享变量的同时,另一个线程正在修改该变量,这就可能导致读取到的数据是脏数据(脏数据是指在并发环境下,一个线程正在修改某个共享变量的同时,另一个线程正在读取同一个变量的值,从而导致读取到的值不正确或者不符合预期。这种情况也被称为“读写冲突”。)或者不符合预期的结果。为了保证线程安全,需要采取相应的措施来避免这类问题。

2.1观察线程不安全

我们写一个程序来观察

// 此处定义⼀个 int 类型的变量
private static int count = 0;
public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {
// 对 count 变量进⾏⾃增 5w 次for (int i = 0; i < 50000; i++) {count++;}});Thread t2 = new Thread(() -> {// 对 count 变量进⾏⾃增 5w 次for (int i = 0; i < 50000; i++) {count++;}});t1.start();t2.start();// 如果没有这俩 join, 肯定不⾏的. 线程还没⾃增完, 就开始打印了. 很可能打印出来的 cout1.join();t2.join();// 预期结果应该是 10wSystem.out.println("count: " + count);
}

       我们运行结果会发现每次运行的结果都是不一样的,这就是因为线程不安全所以我们的结果不正确。上⾯的线程不安全的代码中, 涉及到多个线程针对 count 变量进⾏修改. 此时这个 count 是⼀个多个线程都能访问到的 "共享数据"

2.2线程不安全的原因

1.根本原因:操作系统上的线程是“抢占式执行”“随机调度”=>线程之间执行的顺序带来了很多变数

2.代码结构:代码中多个线程,同时修改同一个变量

一个线程修改一个变量,没事

多个线程读取同一个变量,没事

多个线程修改不同变量,没事

3.直接原因:上述多线程修改操作,本身不是“原子的”(原子性是指一个操作是不可中断的,在执行过程中不能被其他线程或事件打断,要么全部执行成功,要么全部不执行。如果一个操作具有原子性,那么多个线程同时执行这个操作时,不会出现数据不一致的问题。)

3.synchronized 关键字 - 监视器锁 monitor lock

         synchronized是Java中用于实现同步的关键字,可以将代码块或方法声明为同步代码块或同步方法。在多线程环境下,使用synchronized可以确保同一时间只有一个线程能够访问共享资源,从而避免数据不一致的问题。

3.1synchronized 的特性

1. 互斥

        synchronized 会起到互斥效果, 某个线程执⾏到某个对象的 synchronized 中时, 其他线程如果也执⾏到同⼀个对象 synchronized 就会阻塞等待.
进⼊ synchronized 修饰的代码块, 相当于 加锁
退出 synchronized 修饰的代码块, 相当于 解锁

2.可重⼊

         synchronized 同步块对同⼀条线程来说是可重⼊的,不会出现⾃⼰把⾃⼰锁死的问题;

 应用示例:

我们对count进行加锁

package 多线程;public class ThreadDemo14 {private static int count = 0;public static void main(String[] args) throws InterruptedException {//创建一个对象Object locker = new Object();Thread t1 = new Thread(()->{for (int i = 0; i < 5000; i++) {synchronized (locker) {//进程如{}就会加锁count++;}//出了{}就会解锁}});Thread t2 = new Thread(()->{for (int i = 0; i < 5000; i++) {synchronized (locker) {count++;}}});t1.start();t2.start();// 如果没有这俩 join, 肯定不⾏的. 线程还没⾃增完, 就开始打印了. t1.join();t2.join();// 预期结果应该是 10wSystem.out.println("count: " + count);}

 这样我们的结果就正确了。

3.2synchronized 使⽤⽰例  

1. 修饰代码块: 明确指定锁哪个对象.

锁任意对象
public class SynchronizedDemo {private Object locker = new Object();public void method() {synchronized (locker) {}}
}
锁当前对象
public class SynchronizedDemo {public void method() {synchronized (this) {}}
}

2.直接修饰普通⽅法: 锁的 SynchronizedDemo 对象

public class SynchronizedDemo {public synchronized void methond() {}
}

3.修饰静态⽅法: 锁的 SynchronizedDemo 类的对象

public class SynchronizedDemo {public synchronized static void method() {}
}

                                                                   希望大家多多支持!

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

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

相关文章

kotlin flatten 与 flatMap

kotln中 flatten 和 flatMap 在 Kotlin 中虽然都用于扁平化处理集合&#xff0c;但它们的用法和效果并不完全一样 flatten flatten 函数主要应用于嵌套集合&#xff08;如 List of List 或 Set of Set 等&#xff09;&#xff0c;它会将嵌套集合中的所有元素合并到一个单一层…

【MySQL】MySQL 8.0 状态变量(Server Status Variables)以及SHOW STATUS命令

文章目录 【MySQL】MySQL 8.0 状态变量&#xff08;Server Status Variables&#xff09;以及SHOW STATUS命令SHOW STATUS命令查看所有的状态变量查看特定状态变量 参考 【声明】文章仅供学习交流&#xff0c;观点代表个人&#xff0c;与任何公司无关。 编辑|SQL和数据库技术(I…

【Vue】双向绑定 v-model

<script setup>import { reactive,ref} from vue let hbs ref([]); //装爱好的值 </script><template><div>吃 <input type"checkbox" name"hbs" v-model"hbs" value"吃"> 喝 <input type"che…

C++Linux网络编程基础

动态库和静态库 当动态库和静态库同时存在的时候&#xff0c;会优先使用动态库。 静态库 1. 制作静态库 g -c -o lib库名.a 源文件代码清单-c表示只编译&#xff0c;-o则是说明需要指定文件名 2. 使用静态库 g 选项 源代码文件名清单 -l库名 -L库文件所在的目录名3. 库文…

conda国内加速

1、配置国内源 conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ 2、显示源地址 conda config --set show_channel_urls yes

【Arduino】基于 I2C 模块通过 I2C 接口驱动 LCD1602 字符液晶显示模块显示文本:只需两个引脚即可控制 LCD1602 液晶屏

引言 LCD1602是一种16列2行的字符液晶显示模块&#xff0c;常用于Arduino等嵌入式系统的用户接口。为了简化连接和编程&#xff0c;我们将使用I2C接口&#xff0c;这只需要Arduino的两个模拟输入引脚。 步骤 安装 LiquidCrystal_I2C 库 为了在Arduino中使用I2C模块驱动LCD显…

Linux的Shell程序(全面超详细的介绍)

文章目录 前言1.Shell概述1.1概述 2.Shell解析器3.Shell脚本入门4.Shell中的变量4.1 系统变量4.2 自定义变量4.3 特殊变量&#xff1a;$n4.4 特殊变量&#xff1a;$#4.5 特殊变量&#xff1a;\$*、$4.6 特殊变量&#xff1a;$&#xff1f; 5.运算符6.条件判断7.流程控制7.1 if …

五种List集合的简单实现

五种List集合的简单实现 一、数组形式二、单向链表形式三、含哨兵节点的单向链表形式四、含哨兵节点的双向链表形式五、含哨兵节点的环形链表形式 本文是对不同形式List集合的增删改查实现&#xff0c;仅是对学习过程进行记录 一、数组形式 关键点&#xff1a; 有三个成员变量…

Hive-SQL语法大全

Hive SQL 语法大全 基于语法描述说明 CREATE DATABASE [IF NOT EXISTS] db_name [LOCATION] path; SELECT expr, ... FROM tbl ORDER BY col_name [ASC | DESC] (A | B | C)如上语法&#xff0c;在语法描述中出现&#xff1a; []&#xff0c;表示可选&#xff0c;如上[LOCATI…

面试高频知识点:1集合 1.2 ConcurentHashMap是如何实现线程安全的?(1.8之前后区别)

ConcurrentHashMap&#xff08;并发哈希表&#xff09;是Java集合框架中的一种实现Map接口的类&#xff0c;它专为多线程环境设计&#xff0c;以提供更好的性能和线程安全。在理解 ConcurrentHashMap 是如何实现线程安全的时候&#xff0c;我们可以分别探讨 JDK 1.8 之前和之后…

CGAL 网格法向量计算

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 在计算机图形三维曲面中,严格意义上来讲其实并不存在我们数学层面上所定义的曲面结构,因为计算机中的曲面图形一般都是有一个个三角形或者是多边形而组成的,因此所谓曲面的法向量其实就是在计算每一个三角形或多…

【操作系统和计网从入门到深入】(五)软硬链接和动静态库

前言 这个专栏其实是博主在复习操作系统和计算机网络时候的笔记&#xff0c;所以如果是博主比较熟悉的知识点&#xff0c;博主可能就直接跳过了&#xff0c;但是所有重要的知识点&#xff0c;在这个专栏里面都会提到&#xff01;而且我也一定会保证这个专栏知识点的完整性&…

Lombok:简化JavaBeans的神器

前言 Lombok 是一个 Java 库&#xff0c;它通过注解的方式帮助我们自动生成构造器、getter/setter、equals、hashCode、toString 等方法&#xff0c;极大地简化了 JavaBean 的编写。对于经常需要编写大量的样板代码的工作来说&#xff0c;Lombok 提供了一种优雅的解决方案。 …

Linux内核--网络协议栈(四)sk_buff介绍

目录 一、引言 二、sk_buff ------>2.1、skb介绍 ------>2.2、控制字段 ------>2.3、其他字段 ------>2.4、特定功能字段 ------>2.5、管理字段 ------>2.6、内存分配 ------>2.7、内存释放 ------>2.8、克隆和拷贝 ------>2.9、队列管理…

通信入门系列——连续卷积定理、循环卷积、离散卷积定理

本节目录 一、连续卷积定理 1、时域卷积定理 2、频域卷积定理 二、循环卷积 三、离散卷积定理本节内容 一、连续卷积定理 卷积定理在信号分析中占有重要的地位&#xff0c;包括时域卷积定理和频域卷积定理。在信号分析领域&#xff0c;通常采用基于卷积定理的时频域分析&#…

Zuul1.x 高并发下阻塞分析以及解决方案

背景 由于最近博主在压测接口的时候发现我接口出现卡死状态&#xff0c;最开始以为是我自己接口出现问题&#xff0c;单独压测我自己的服务&#xff08;不经过网关&#xff09;200/qps/10 次循环 是没问题&#xff0c;但是加上网关&#xff08;zuul 1.x&#xff09; 去发现 经…

编曲学习:Cubase12导入Cubasis工程的方法!

Steinberg 发布 Cubasis 3 项目导入器&#xff0c;可将 Cubasis 的项目导入到 Cubase 使用https://m.midifan.com/news_body.php?id35635 我偶然看到这个文章&#xff0c;不过发现Cubase12默认好像没有这个选项&#xff0c;心想着要是移动端能和PC端同步&#xff0c;感觉会挺…

【网站项目】基于jsp的199旅游景点管理系统

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

C++中的排序操作:sort与自定义排序(自定义排序函数、匿名函数、运算符重载)

在C编程中&#xff0c;排序是一项常见而又重要的操作。本文将深入介绍C标准库中的sort算法&#xff0c;以及如何利用其强大的自定义排序功能满足各种排序需求。 sort算法简介 C标准库提供了sort算法&#xff0c;能够在O(N log N)的时间内对容器中的元素进行排序。这一高效的排…

快速下载百度网盘的文件——使用motrix

问题描述 下载速度慢 上传速度快 解决方案&#xff1a; Motrix 在该开源程序里面 选windows选择zip 启动之后 &#xff0c;把百度网盘的链接转化成磁力链接。然后输入转化后的连接。转换的网页 每次设置下载认任务是选择高级选项里面的请求头 修改为LogStatistic 然后就能超…