深入理解Java中的synchronized关键字

目录

前言

一、什么是synchronized

二、synchronized的底层实现

三、synchronized与其他同步机制的比较

四、synchronized的使用方式

1. synchronized的重入

2.synchronized的异常


前言

        Java是一种面向对象的编程语言,以其强大的并发处理能力而闻名。在多线程编程中,保证线程安全是一个重要的问题。本文将详细探讨Java中的一个关键机制——synchronized关键字,帮助你深刻理解其概念、使用方法及其背后的工作原理。

一、什么是synchronized

   synchronized是Java提供的一种内置同步机制,用于解决多线程环境下的并发问题。当多个线程同时访问共享资源时,可能会出现数据不一致的情况。synchronized通过锁(monitor)的方式来确保同一时间只有一个线程可以访问被保护的代码块,从而避免数据的竞争问题。

二、synchronized的底层实现

        Java中synchronized关键字是通过进入和退出Monitor(监视器)对象来实现的。每个对象都有一个隐式的监视器锁。当我们使用synchronized同步方法或同步代码块时,线程必须先获得该锁才能进入同步区域。

        在JVM内部synchronized是通过字节码指令monitorentermonitorexit来实现的。当线程执行到synchronized区域时,它会尝试获取对象的监视器锁。若成功,则进入同步区域;否则,线程会被阻塞,直到获得锁为止。

三、synchronized与其他同步机制的比较

除了synchronized之外,Java还提供了其他一些高级的同步机制,如ReentrantLockSemaphore等。以下是它们的一些比较:

  • 可重入性synchronizedReentrantLock都是可重入锁。可重入性意味着同一个线程可以多次进入同步代码块而不会被自己阻塞。

  • 灵活性ReentrantLocksynchronized更加灵活。它提供了更多的方法,例如lockInterruptibly()tryLock()等,可以更精细地控制锁的行为。

  • 性能:在较早版本的Java中,synchronized的性能表现较差。但从Java 6开始,JVM对synchronized做了诸多优化,如偏向锁、轻量级锁以及自旋锁等,使其性能有了显著提升。

  • 条件变量ReentrantLock提供了Condition类,可以实现多个等待队列,配合await()signal()方法实现更加复杂的线程间通信。而synchronized只能依赖于wait()notify()notifyAll()方法来管理线程间的通信。

四、synchronized的使用方式

        关键字synchronized拥有锁重入的功能,也就是在使用synchronized时,当一个线程得到了一个对象的锁后,再次请求此对象时是可以再次得到该对象的锁。出现异常,锁自动释放。

1. synchronized的重入

package com.ctb.sync5;
/*** synchronized的重入* * @author biao** 2024年*/
public class SyncDubbo1 {
​public synchronized void method1(){System.out.println("method1..");method2();}public synchronized void method2(){System.out.println("method2..");method3();}public synchronized void method3(){System.out.println("method3..");}public static void main(String[] args) {final SyncDubbo1 sd = new SyncDubbo1();Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {sd.method1();}});t1.start();}
}

结果: 

注:synchronized的重入,在同时添加都synchronized锁后,在得到一个对象的锁后是可以再次得到该对象的锁的

package com.ctb.sync5;
/*** synchronized的重入* * @author biao** 2024年*/
public class SyncDubbo2 {
​static class Main {public int i = 10;public synchronized void operationSup(){try {i--;System.out.println("Main print i = " + i);Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}static class Sub extends Main {public synchronized void operationSub(){try {while(i > 0) {i--;System.out.println("Sub print i = " + i);Thread.sleep(100);      this.operationSup();}} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) {Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {Sub sub = new Sub();sub.operationSub();}});t1.start();}}
​

注:也可以通过继承的方式进行synchronized的重入

2.synchronized的异常

        对于web应用程序,异常释放锁的情况,如果不及时处理,很可能对你的应用程序业务逻辑产生严重的错误,比如你现在执行一个队列任务,很多对象都在去等待第一个对象正确执行完毕再去释放锁,但是第一个对象由于异常的出现,导致业务逻辑没有正常执行完毕。所以这一点一定要引起注意,在编写代码的时候,一定要考虑周全。

package com.ctb.sync5;
/*** synchronized的异常* * @author biao** 2024年*/
public class SyncException {
​private int i = 0;public synchronized void operation(){while(true){try {i++;Thread.sleep(200);System.out.println(Thread.currentThread().getName() + " , i = " + i);if(i == 10){Integer.parseInt("a");//throw new RuntimeException();}} catch (Exception e) {//InterruptedExceptione.printStackTrace();System.out.println("log info i = " + i);//throw new RuntimeException();//continue;}}}public static void main(String[] args) {final SyncException se = new SyncException();Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {se.operation();}},"t1");t1.start();}}

结果: 

注:在我们运行数据时,当它某条数据出现错误时,继续往下执行,并记录异常数据,后续根据日志去解决问题。

当然我们也可以在异常产生时进行停止数据的变动,

第一种:抛出运行时异常

public synchronized void operation(){while(true){try {i++;Thread.sleep(200);System.out.println(Thread.currentThread().getName() + " , i = " + i);if(i == 10){Integer.parseInt("a");
//                  throw new RuntimeException();}} catch (Exception e) {//InterruptedExceptione.printStackTrace();System.out.println("log info i = " + i);throw new RuntimeException();
//              continue;}}}

结果: 

        第二种:InterruptedException 是 Java 中的一个受检查异常,表示一个线程被中断。当一个线程调用 Thread 类的 interrupt() 方法时,会给该线程设置一个中断标记,表示该线程被中断了。

public synchronized void operation(){while(true){try {i++;Thread.sleep(200);System.out.println(Thread.currentThread().getName() + " , i = " + i);if(i == 10){Integer.parseInt("a");
//                  throw new RuntimeException();}} catch (InterruptedException e) {//InterruptedExceptione.printStackTrace();System.out.println("log info i = " + i);
//              throw new RuntimeException();
//              continue;}}}

结果: 

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

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

相关文章

LLM 理论知识

LLM 理论知识 一.大型语言模型LLM1.1 大型语言模型 LLM 的概念1.2 常见的 LLM 模型1.2.1 闭源 LLM (未公开源代码)1.2.1.1 GPT 系列1.2.1.1.1 ChatGPT1.2.1.1.2 GPT-4 1.2.1.2 Claude 系列1.2.1.1.3 PaLM/Gemini 系列1.2.1.1.4 文心一言1.2.1.1.5 星火大模型 1.2.2. 开源 LLM1.…

threejs材质的贴图(四)

效果 代码实现 import ./style.css import * as THREE from three import { OrbitControls } from three/examples/jsm/controls/OrbitControls.js//相机轨道控制器 import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js"//加载hdr文件作为环境贴…

排序模型的奥秘:如何用AI大模型提升电商、广告和用户增长的效果

摘要 排序模型是数字化营销中最重要的工具之一,它可以帮助我们在海量的信息中筛选出最符合用户需求和偏好的内容,从而提高用户的满意度和转化率。本文从产品经理的视角,介绍了常见的排序模型的原理和应用,包括基于规则的排序、基…

【ROS1转ROS2示例】

ROS1中的代码: 这是一个循环函数: ros::Rate loop_rate(10); // Adjust the publishing rate as neededwhile (ros::ok()){loop_rate.sleep();} 如果转ROS2,可以使用rclcpp::WallRate或者直接依赖于执行器(Executor)的循环来实现类似的功…

如何有效处理独立站遭受的网络攻击

随着电子商务的蓬勃发展,独立站成为了众多商家展示产品、吸引客户的重要平台。然而,这同时也吸引了不法分子的目光,使得独立站成为网络攻击的重灾区。本文将深入探讨独立站可能遭受的各种网络攻击类型,并提供一系列实用且可运行的…

【C语言初阶】分支语句

🌟博主主页:我是一只海绵派大星 📚专栏分类:C语言 ❤️感谢大家点赞👍收藏⭐评论✍️ 目录 一、什么是语句 二、if语句 悬空else 三、switch语句 default 四、switch语句与if-else语句性能对比如何&#xff1f…

分布式技术导论 — 探索分析从起源到现今的巅峰之旅(消息队列)

探索分析从起源到现今的巅峰之旅 分布式队列 - Kafka架构特性可扩展性磁盘优化与顺序访问大容量存储与历史数据利用高效数据封装与压缩智能内存管理与OS缓存利用 Kafka发布/订阅模型Kafka架构分析Producer和Consumer接口交互Producer通过Topic发送数据Consumer通过Topic消费数据…

springboot项目mapper无法自动装配,未找到 ‘userMapper‘ 类型的Bean解决办法.

一开始我看到了这个回答:springboot项目mapper无法自动装配,未找到 ‘userMapper‘ 类型的 Bean解决办法(含报错原因)_无法自动装配。找不到 usermapper 类型的 bean。-CSDN博客 mapper无法自动装配,未找到 ‘userMap…

MyBatis系列四: 动态SQL

动态SQL语句-更复杂的查询业务需求 官方文档基本介绍案例演示if标签应用实例where标签应用实例choose/when/otherwise应用实例foreach标签应用实例trim标签应用实例[使用较少]set标签应用实例[重点]课后练习 上一讲, 我们学习的是 MyBatis系列三: 原生的API与配置文件详解 现在…

自定义Unity组件——ABManager(AB包管理器)

需求描述 在Unity3D引擎中,AB包作为常用的游戏资源存储格式之一。而对于资源管理我们就不得不谈到集中管理的优势了,通过统一的接口加载和卸载AB包及其中的资源将进一步提升我们的编程效率。本文将围绕这个需求进行尝试。 功能描述 1. AB包的加载包括同…

【C#上位机应用开发实战】—机器视觉检测

#机器视觉 在现代工业生产中,机器视觉检测技术扮演着越来越重要的角色。它通过计算机视觉技术来实现对工件的自动化检测和判断,大大提高了生产效率和产品质量。而在机器视觉检测的应用中,C#作为一种简洁易用且功能强大的编程语言&#xff0c…

报表开发工具DevExpress Reporting v23.2 - 增强PDF导出、多平台打印等

DevExpress Reporting是.NET Framework下功能完善的报表平台,它附带了易于使用的Visual Studio报表设计器和丰富的报表控件集,包括数据透视表、图表,因此您可以构建无与伦比、信息清晰的报表。 DevExpress Reporting控件日前正式发布了v23.2…

ClickHouse安装与下载22.3.2.2

ClickHouse安装与下载 目录 1. ClickHouse简介 1.1 ClickHouse优点: 1.2 ClickHouse缺点: 1.3 ClickHouse引擎: 1.3.1 数据库引擎 1.3.2 表引擎 2. ClickHouse下载安装 2.1 ClickHouse下载安装 2.2 ClickHouse使用 1. ClickHouse简…

中国剩余定理——AcWing 204. 表达整数的奇怪方式

中国剩余定理 定义 中国剩余定理最早出自我国古代的《孙子算经》,是数论中的一个重要定理。它描述了这样一种情况:在模运算下,对于一组线性同余方程组,存在唯一解的条件和求解方法。 运用情况 常用于在一些涉及到按不同模的余…

安全宣传咨询日活动向媒体投稿记住这个投稿好方法

在信息爆炸的时代,作为单位的信息宣传员,我肩负着将每一次重要活动,特别是像“安全宣传咨询日”这样的公益活动,有效传达给公众的重任。这份工作看似简单,实则充满了挑战,尤其是在我初涉此领域时,那段曲折而又难忘的投稿经历,至今记忆犹新。 初探投稿之海,遭遇重重困难 起初,我…

注册安全分析报告:PingPong

前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 暴力破解密码,造成用户信息泄露短信盗刷的安全问题,影响业务及导致用户投诉带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞 …

vscode-关闭ts与js语义校验

1.ts与js语义校验 TypeScript(TS)和JavaScript(JS)在语义校验方面有很大的不同。TypeScript是一种静态类型检查的编程语言,它是JavaScript的一个超集,为JavaScript添加了类型系统和其他一些特性。而JavaScr…

12.爬虫---PyMysql安装与使用

12.PyMysql安装与使用 1.安装 PyMySQL2.使用PyMySQL2.1创建数据表2.2连接数据库2.3增加数据2.4修改数据2.5查询数据2.6删除数据2.7关闭连接 3.总结 1.安装 PyMySQL PyMySQL是Python中用于连接MySQL数据库的库,安装起来非常简单。通常情况下,只需要在命令…

从零开始:精通基于大型语言模型(LLM)的Agent应用开发

一、引言 随着人工智能技术的飞速发展,大型语言模型(Large Language Model,简称LLM)已经成为自然语言处理(NLP)领域的核心技术之一。这些模型,如GPT、BERT等,通过大量的文本数据训练…

八个精品ETL工具,总有一款适合您的业务需求!

在数字经济高速发展的今天,数据的价值愈发凸显。ETL(Extract, Transform, Load)工具作为数据集成的关键一环,不仅帮助企业高效管理海量数据,还能为商业决策提供实时洞察。本文将深入探讨目前市场上的8款领先ETL工具&am…