Java中的监视器锁 (synchronized 关键字)

在使用多线程的时候,我们会经常遇到线程不安全的问题,即多个线程访问共享数据时出现不确定的结果或异常,此时引入我们今天要介绍的synchronized 关键字


一.synchronized 的特性

1) 互斥

synchronized 会起到互斥效果, 某个线程执行到某个对象的 synchronized 中时, 其他线程如果也执行到同一个对象 synchronized 就会阻塞等待.

进入 synchronized 修饰的代码块, 相当于 加锁

退出 synchronized 修饰的代码块, 相当于 解锁

public class SynchronizedTest {//进入increase方法内部->加锁//此时其他对象访问increase方法时将会停滞等待synchronized void increase(int count){count++;}//此时increase方法执行完毕->解锁//其它对象可以访问increase方法
}

2) 刷新内存

synchronized 的工作过程:  

1. 获得互斥锁

2. 从主内存拷贝变量的最新副本到工作的内存

3. 执行代码

4. 将更改后的共享变量的值刷新到主内存

5. 释放互斥锁 所以 synchronized 也能保证内存可见性.

(内存可见性是指当一个线程修改了共享变量的值后,其他线程能够立即看到这个修改后的值)

3) 可重入

synchronized 同步块对同一条线程来说是可重入的,不会出现自己把自己锁死的问题;

自己锁自己:对于某些锁,在加锁后没有释放,而又加了一个锁后,会与前面的锁互斥而锁死

而synchronized是可重入锁,不会出现上述问题

public class SynchronizedTest {synchronized void increase1(int count){count++;}synchronized void increase2(int count){increase1(count);}public void test() {int count=0;increase2(count);//此时会先调用increase2(),再调用increase1(),//因为synchronized是可重入锁,所以不会出现卡死现象}
}

可重入锁的原理:

在可重入锁的内部, 包含了 "线程持有者" "计数器" 两个信息. 如果某个线程加锁的时候, 发现锁已经被人占用, 但是恰好占用的正是自己, 那么仍然可以继续获取到锁, 并让计数器自增. 解锁的时候计数器递减为 0 的时候, 才真正释放锁. (才能被别的线程获取到)

二.synchronized 所锁的对象

我们说当不同线程获取同一把锁时,才会出现锁互斥,才能保证线程安全,那么怎样判断是不是同一把锁呢?

在上面的例子中,synchronized关键字都是修饰在increase方法中的,那么锁的对象是increase()方法吗?显然不是,锁的是调用increase()方法的对象;

现在我们分几种情况讨论锁的对象有哪些:

1) 修饰普通方法:

锁的是调用普通方法的对象

class Add{public synchronized void increase3(int count){count++;} 
}class Test{public static void main(String[] args) {int count=0;//将Add类实例化,得到对象addAdd add=new Add();//使add对象调用increase3方法add.increase3(count);//此时锁的对象就是add}
}

2) 修饰静态方法:

锁的是方法所属的类的对象

//这是一个类,它的名称为Add,里面有一个被synchronized修饰的静态方法
//注意:方法increase3已改为静态方法
class Add{public static synchronized void increase3(int count){count++;}
}class Test{public static void main(String[] args) {int count=0;//静态方法可以不用实例化而直接调用Add.increase3(count);//此时锁的对象为Add类,本质是Add的class,即Add.class}
}

3) 修饰代码块:

自己明确指定锁哪个对象

我们不一定要用锁去修饰方法,而是可以修饰方法中的某一部分,即修饰自己想要修饰的代码

同时,我们就要自己选择所锁的对象了

1.锁当前对象
class Add2{public void increase4(int count){System.out.println("下面是我们要修饰的代码块");//this即调用increase4的对象synchronized (this){count++;}}
}
class Test{public static void main(String[] args) {Add2 add2=new Add2();add2.increase4(count);//此时锁的对象就是add2//和第一种本质上是一样的,只是锁所管辖的范围不一样了而已}
}
2.锁类对象
class Add2{public static void increase4(int count){System.out.println("下面是我们要修饰的代码块");//锁的对象是Add.class对象synchronized (Add2.class){count++;}}
}
class Test{public static void main(String[] args) {Add2.increase4(count);//此时锁的对象为Add类,本质是Add的class,即Add.class//和第二种本质上是一样的,同样是锁所管辖的范围不一样了而已}
}

我们重点要理解,synchronized 锁的是什么. 两个线程竞争同一把锁, 才会产生阻塞等待.

此时我们就可以更好的理解可重入锁中所描述的同一个对象是什么了

三.Java 标准库中的线程安全类

在日常的使用中,我们要了解一些常用的安全与不安全类

1)不安全的类

Java 标准库中很多都是线程不安全的. 这些类可能会涉及到多线程修改共享数据, 又没有任何加锁措施.

ArrayList

LinkedList

HashMap

TreeMap

HashSet

TreeSet

StringBuilder

2)安全的类

但是还有一些是线程安全的. 使用了一些锁机制来控制.

Vector (不推荐使用)

HashTable (不推荐使用)

ConcurrentHashMap

StringBuffer

还有的虽然没有加锁, 但是不涉及 "修改", 仍然是线程安全的

String类


那么到这里,有关synchronize的基本介绍就结束了~

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

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

相关文章

手机运营商二要素检测:重塑信任基石,筑牢信息安全屏障

随着移动互联网的普及和数字经济的快速发展,用户信息安全的重要性日益凸显。运营商二要素检测作为一种强大的安全验证机制,以其精准匹配与实时验证的特性,为各类应用场景提供了一种可靠的身份识别解决方案,正在成为众多企业和服务…

PyTorch 深度学习(GPT 重译)(六)

十四、端到端结节分析,以及接下来的步骤 本章内容包括 连接分割和分类模型 为新任务微调网络 将直方图和其他指标类型添加到 TensorBoard 从过拟合到泛化 在过去的几章中,我们已经构建了许多对我们的项目至关重要的系统。我们开始加载数据&#xf…

11种创造型设计模式(下)

观察者模式 我们可以比喻观察者模式是一种类似广播的设计模式 介绍 观察者模式:对象之间多对一依赖的一种设计方案,被依赖的对象是Subject,依赖的对象是Observer,Subject通知Observer变化。 代码 说明: WeatherStat…

【百度灵境矩阵实训营】操作指南

【百度灵境矩阵实训营】操作指南 写在最前面提交注意事项比赛参与指南1、创建智能体作品要求 2、提交作品 学习资料包 🌈你好呀!我是 是Yu欸 🌌 2024每日百字篆刻时光,感谢你的陪伴与支持 ~ 🚀 欢迎一起踏上探险之旅&…

Docker容器化技术(docker-compose示例:部署discuz论坛和wordpress博客,使用adminer管理数据库)

安装docker-compose [rootservice ~]# systemctl stop firewalld [rootservice ~]# setenforce 0 [rootservice ~]# systemctl start docker[rootservice ~]# wget https://github.com/docker/compose/releases/download/v2.5.0/docker-compose-linux-x86_64创建目录 [rootse…

用纯C语言实现空气压强和电压关系

已知P是真空度&#xff0c;U是电压&#xff0c;C是3.572&#xff08;以PA为单位&#xff09;&#xff0c;P10**(U-C)/1.286 1、使用 math.h 头文件中提供的函数&#xff0c;比如 pow() 来计算幂 #include <stdio.h> #include <math.h>int main() {double U; // 电…

​LeetCode解法汇总1969. 数组元素的最小非零乘积

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给你一个正整数 p 。你有一个下标从 1 开…

exiftool对视频信息进行读取修改

​ 安装 ExifTool 首先&#xff0c;你需要在你的计算机上安装 ExifTool。你可以从 ExifTool 官方网站 下载适合你操作系统的版本。修改视频元数据 安装完成后&#xff0c;你可以使用 ExifTool 的命令行接口来修改视频文件的元数据。以下是一个基本的命令示例&#xff0c;用于修…

接口测试、postman、测试点提取【主】

接口测试是测试系统组件间接口的一种测试 接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点 测试的重点是要检查数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及系统间的相互逻辑依赖关系 文章目录 HTTP接口 & Web Service接口RESTful接口…

SQLiteC/C++接口详细介绍sqlite3_stmt类(五)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLiteC/C接口详细介绍sqlite3_stmt类&#xff08;四&#xff09;- 下一篇&#xff1a; 无 12. sqlite3_bind_text16函数 sqlite3_bind_text16函数用于将UTF-16编码的文本数据&#xff08;字符串&#xff09;绑定…

Hive自定义UDF函数

Hive自定义UDF函数 1. 准备Java开发环境&#xff1a;确保在开发机器上安装了Java开发环境。 2. 创建一个Java项目&#xff1a;创建一个新的Java项目&#xff0c;用于编写Hive UDF函数。 3. 导入Hive依赖&#xff1a;在项目中导入Hive的依赖&#xff0c;以便能够访问Hive的相…

语音识别教程:Whisper

语音识别教程&#xff1a;Whisper 一、前言 最近看国外教学视频的需求&#xff0c;有些不是很适应&#xff0c;找了找AI字幕效果也不是很好&#xff0c;遂打算基于Whisper和GPT做一个AI字幕给自己。 二、具体步骤 1、安装FFmpeg Windows: 进入 https://github.com/BtbN/FF…

[嵌入式系统-43]:SOC芯片内部的总线规范

目录 一、SOC&#xff08;System on Chip&#xff09; 二、AMBA 2.1 AMBA概述 2.2 AMBA架构 三、AXI 2.1 AXI概述 一、SOC&#xff08;System on Chip&#xff09; SOC&#xff08;System on Chip&#xff09;通常包含多个功能模块&#xff0c;如处理器核心、内存控制器…

综合知识篇16-信息系统基础知识考点(2024年软考高级系统架构设计师冲刺知识点总结系列文章)

专栏系列文章: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12593400.html案例分析篇00-【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例…

基于SpringBoot和Vue的网上订餐系统的设计与实现

今天要和大家聊的是一款基于SpringBoot和Vue的网上订餐系统的设计与实现。 &#xff01;&#xff01;&#xff01; 有需要的小伙伴可以通过文章末尾名片咨询我哦&#xff01;&#xff01;&#xff01; &#x1f495;&#x1f495;作者&#xff1a;李同学 &#x1f495;&#x…

nginx介绍及搭建

架构模型 Nginx是由一个master管理进程、多个worker进程组成的多进程模型。master负责管理worker进程&#xff0c;worker进程负责处理网络事件&#xff0c;整个框架被设计为一种依赖事件驱动、异步、非阻塞的模式。 优势&#xff1a; 1、充分利用多核&#xff0c;增强并发处理…

深入理解快速排序算法

介绍 快速排序&#xff08;Quick Sort&#xff09;是一种极其重要且有实际意义的经典算法&#xff0c;广泛应用于各种排序函数&#xff0c;由其名称也可知道其主要特点&#xff1a;快速 快速排序通过递归地将数组分割成较小的子集并对子集进行排序来实现。其核心思想是选取一…

Docker 哲学 - ip 的组成规则 与 网关介绍

在 IP 地址中&#xff0c;我们通常将 IP 地址分为两部分&#xff1a;网络部分和主机部分。网络部分用于标识网络&#xff0c;主机部分用于标识该网络中的特定主机。 IP 地址的每个部分&#xff08;也被称为一个八位组或一个字节&#xff09;可以是从0到255的任何值。 一个 IPv4…

[隐私计算实训营学习笔记] 第1讲 数据要素流通

信任四基石 数据的分级分类 技术信任&#xff1a;全链路审计、闭环完成的数据可信流通体系 技术信任&#xff1a;开启数据密态时代 数据可流通的基础设施&#xff1a;密态天空计算

LeetCode 面试经典150题 罗马数字转整数

题目&#xff1a; 罗马数字包含以下七种字符: 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 …