JAVA锁机制:对象锁与类锁

JAVA锁机制:对象锁与类锁

在多线程编程中,合理使用锁机制是保证数据一致性和线程安全的关键。本文将通过示例详细讲解 Java 中的对象锁和类锁的原理、用法及区别。

一、未加锁的并发问题

先看一段未加锁的代码:

public class SynchronizedTest {private int shareField = 0;public void add() {shareField++;System.out.println("当前线程:" + Thread.currentThread().getName() + " 当前的shareField为:" + shareField);}public static void main(String[] args) {SynchronizedTest sync = new SynchronizedTest();new Thread(() -> {for (int n = 0; n < 100000; n++) {sync.add();}}).start();new Thread(() -> {for (int n = 0; n < 100000; n++) {sync.add();}}).start();}
}

上述代码启动两个线程,每个线程各自循环10万次,对 shareField 进行自增。理论上,最终 shareField 应为 200000,但实际运行结果往往小于 200000:

当前线程:Thread-0 当前的shareField为:199994
当前线程:Thread-0 当前的shareField为:199995
...

原因在于多个线程并发修改同一变量,导致数据竞争。


二、对象锁

对象锁用于保护同一个实例的资源,确保同一时刻只有一个线程能访问被锁定的代码块。

1. 锁定非静态方法

public class SynchronizedTest {private int shareField = 0;public synchronized void add() {shareField++;System.out.println("当前线程:" + Thread.currentThread().getName() + " 当前的shareField为:" + shareField);}// 省略 main 方法
}

synchronized 修饰非静态方法时,锁的是当前实例对象 (this)。

2. 锁定 this 对象(代码块)

有时只需对方法中的部分代码加锁,可以使用同步代码块:

public void add() {synchronized (this) {shareField++;System.out.println("当前线程:" + Thread.currentThread().getName() + " 当前的shareField为:" + shareField);}
}

3. 锁定特定对象

也可以指定其他对象作为锁:

private final Object obj = new Object();
public void add() {synchronized (obj) {shareField++;System.out.println("当前线程:" + Thread.currentThread().getName() + " 当前的shareField为:" + shareField);}
}
对象锁特点
  • 锁对象:当前实例(this)或指定对象
  • 多线程访问同一实例的同步方法时互斥
  • 不同实例之间互不影响

三、类锁

类锁用于保护类级别的资源(如静态变量),确保同一时刻只有一个线程能访问被锁定的静态资源。

1. 锁定静态方法

public static synchronized void add() {shareField++;System.out.println("当前线程:" + Thread.currentThread().getName() + " 当前的shareField为:" + shareField);
}

synchronized 修饰静态方法时,锁的是类的 Class 对象。

2. 锁定 class 对象

public void add() {synchronized (SynchronizedTest.class) {shareField++;System.out.println("当前线程:" + Thread.currentThread().getName() + " 当前的shareField为:" + shareField);}
}

3. 锁定静态实例变量

private static final Object obj = new Object();
public void add() {synchronized (obj) {shareField++;System.out.println("当前线程:" + Thread.currentThread().getName() + " 当前的shareField为:" + shareField);}
}
类锁特点
  • 锁对象:类的 Class 对象或静态实例变量
  • 所有实例共享同一把锁,实现全局互斥

四、对象锁与类锁的区别

选择对象锁还是类锁,取决于需要保护的变量是实例级还是类级(静态)。

例如:

public class SynchronizedTest {private static int shareField = 0;public void add() {synchronized (this) {shareField++;System.out.println("当前线程:" + Thread.currentThread().getName() + " 当前的shareField为:" + shareField);}}public static void main(String[] args) {new Thread(() -> {SynchronizedTest sync1 = new SynchronizedTest();for (int n = 0; n < 100000; n++) {sync1.add();}}).start();new Thread(() -> {SynchronizedTest sync2 = new SynchronizedTest();for (int n = 0; n < 100000; n++) {sync2.add();}}).start();}
}

上述代码中,两个线程分别操作不同实例,但都修改静态变量 shareField。此时对象锁无法保证线程安全,需使用类锁:

public void add() {synchronized (SynchronizedTest.class) {shareField++;System.out.println("当前线程:" + Thread.currentThread().getName() + " 当前的shareField为:" + shareField);}
}

五、总结

特性对象锁类锁
锁对象当前实例(this)/obj类的Class对象/静态实例变量
作用范围同一实例间互斥所有实例间互斥
适用场景保护实例级变量保护类级变量(静态变量)
并发影响不同实例间无互斥所有实例共享同一把锁
实现方式synchronized方法/代码块static synchronized方法/class锁对象

合理选择锁的类型,是实现高效并发和线程安全的关键。

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

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

相关文章

maxcomputer 和 hologres中的EXTERNAL TABLE 和 FOREIGN TABLE

在阿里云的大数据和实时数仓产品中&#xff0c;MaxCompute 和 Hologres 都支持类似于 EXTERNAL TABLE 和 FOREIGN TABLE 的机制&#xff0c;但它们的实现和语义有所不同。 下面分别说明&#xff1a; ☁️ 一、MaxCompute 中的 EXTERNAL TABLE 和 FOREIGN TABLE 1. EXTERNAL T…

稳定币:从支付工具到金融基础设施的技术演进与全球竞争新格局

引言&#xff1a;稳定币的崛起与金融体系重构 2025年6月&#xff0c;全球稳定币市值突破2500亿美元历史大关&#xff0c;单年链上交易额高达35万亿美元——这一数字已超越Visa和万事达卡交易总和。这一里程碑事件标志着稳定币已从加密货币市场的边缘实验&#xff0c;蜕变为重构…

用 HTML、CSS 和 jQuery 打造多页输入框验证功能

多页输入框验证功能总结:使用 HTML、CSS 和 jQuery 实现 一、多页表单验证的核心概念与应用场景 多页输入框验证是指将复杂表单拆分为多个页面或步骤,逐步引导用户完成输入,并在每一步对用户输入进行验证的功能。这种设计具有以下优势: 提升用户体验:避免长表单带来的心…

DeepSpeed 深度学习学习笔记:高效训练大型模型

主要参考官网文档&#xff0c;对于具体内容还需参考官方文档 1. 引言&#xff1a;为什么需要 DeepSpeed&#xff1f; 大型模型训练的挑战 随着深度学习模型规模的爆炸式增长&#xff08;从 BERT 的几亿参数到 GPT-3 的千亿参数&#xff0c;再到现在的万亿参数模型&#xff09…

编程基础:耦合

能帮到你的话&#xff0c;就给个赞吧 &#x1f618; 文章目录 耦合&#xff1a;功能的单一性&#xff0c;功能越拆分则单一功能越好维护 耦合&#xff1a;功能的单一性&#xff0c;功能越拆分则单一功能越好维护

基于Qt的UDP主从服务器设计与实现

概述 一个基于Qt框架实现的UDP主从服务器系统&#xff0c;该系统具备自动主机选举、故障转移和状态同步等关键功能&#xff0c;适用于分布式能源管理系统中的设备通信与协调。 系统核心功能 1. 自动主机选举与故障转移 系统通过优先级机制实现自动主机选举&#xff0c;当主机…

【51单片机2位数码管100毫秒的9.9秒表】2022-5-16

缘由 这一题刚设计好要去回复就看到结帖了&#xff0c;好似看到我设计完成就盗窃去了&#xff0c;如此下面类似题目很容易也懒得回复了。 #include "reg52.h" sbit k0P3^0; sbit k1P3^1; unsigned char code SmZiFu[]{63,6,91,79,102,109,125,7,127,111};//0-9 uns…

安装ClickHouse

安装ClickHouse ClickHouse是一个用于联机分析的列式数据库管理系统&#xff0c;主要用于在线分析处理查询&#xff08;OLAP&#xff09;&#xff0c;能够使用SQL查询实时生成分析数据报告。 ClickHouse是一个完全的列式数据库管理系统&#xff0c;允许在运行时创建表和数据库&…

PX4无人机集成自带的深度相机进行gazebo仿真

修改mavros_posix_sitl.launch文件 修改以下两行代码 <arg name"my_model" default"iris_depth_camera"/><arg name"sdf" default"$(find mavlink_sitl_gazebo)/models/$(arg my_model)/$(arg my_model).sdf"/>iris_dept…

正点原子STM32cubeide学习——TFTLCD(MCU 屏)实验

使用的是正点原子的精英版&#xff0c;单片机是STM32F103ZET6&#xff0c;使用开发板的 MCU 屏接口连接正点原子 TFTLCD 模块(仅限 MCU 屏模块)&#xff0c;实现 TFTLCD 模块的显示。通过把 LCD 模块插入底板上的 TFTLCD 模块接口&#xff0c;按下复位之后&#xff0c; 就可以看…

OpenCV实现二值图细化(骨架提取)

对二值图进行细化&#xff08;骨架提取&#xff09;&#xff0c;也就是把每根线条细化到一个像素的宽度。有两个比较成熟的算法实现此功能&#xff0c;分别是Zhang-Suen算法和Guo-Hall算法。 我们下面使用OpenCVSharp&#xff0c;使用C#实现上述两个算法&#xff1a; private…

历史的迷雾与传承的使命:应对历史篡改,守护中华文明

在历史的浩瀚长河中&#xff0c;中国以悠久的文明与灿烂的文化屹立于世界东方。然而&#xff0c;满清时期与西方势力出于各自目的对中国历史进行篡改&#xff0c;在真实历史的画卷上蒙上了层层迷雾。深入探究其背后的动机&#xff0c;思考当代人守护历史文化的使命&#xff0c;…

【Qt】QTableWidget表格右键菜单

效果 1. 给QTableWidget组件添加customContextMenuRequested信号 2. 槽函数 void dataDetailForm::on_tableWidget_customContextMenuRequested(const QPoint &pos) {QMenu menu;QAction *setEnd menu.addAction(tr("设置"));connect(setEnd, SIGNAL(triggered…

MySQL 数据处理函数全面详解

MySQL 数据处理函数全面详解 MySQL 中的数据处理函数,包含字符串、数值、日期、条件判断等核心函数: 一、字符串处理函数 1. 基础操作函数 函数描述示例结果CONCAT()字符串连接CONCAT(My,SQL)‘MySQL’CONCAT_WS()带分隔符连接CONCAT_WS(-,2023,08,15)‘2023-08-15’LENGTH…

领域驱动设计(DDD)【1】之初步理解

文章目录 一 DDD概述二 从“沉寂”到“爆火”&#xff1a;DDD的兴起背景与原因2.1 DDD早期沉寂的原因2.2 DDD近年爆火的原因2.3 总结 三 DDD深入理解3.1 方法论本质3.2 系统化价值3.3 思想内核3.4 实践转化3.5 总结 四 传统面向对象方法学和DDD4.1 传统面向对象方法学的问题4.2…

人工智能学习57-TF训练

人工智能学习概述—快手视频 人工智能学习57-TF训练—快手视频 人工智能学习58-TF训练—快手视频 人工智能学习59-TF预测—快手视频 训练示例代码 #导入keras.utils 工具包 import keras.utils #导入mnist数据集 from keras.datasets import mnist #引入tensorflow 类库 …

MySQL(83)如何设置密码复杂度策略?

在 MySQL 中&#xff0c;可以通过配置密码策略来设置密码的复杂度要求。MySQL 提供了一些参数和插件来帮助管理员强制实施密码复杂度策略&#xff0c;确保数据库用户使用强密码。下面将详细介绍如何设置密码复杂度策略&#xff0c;并结合代码示例进行说明。 1. 使用 validate_…

如何使用postman做接口自动化测试?

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 本文适合已经掌握 Postman 基本用法的读者&#xff0c;即对接口相关概念有一定了解、已经会使用Postman 进行模拟请求等基本操作。 工作环境与版本&#xff1a; …

面试-操作系统

用户态和内核态的区别 内核态&#xff1a;在内核态下&#xff0c;CPU可以执行所有的指令和访问所有的硬件资源。 用户态&#xff1a;在用户态下&#xff0c;CPU只能执行部分指令集&#xff0c;无法直接访问硬件资源。 内核态的底层操作主要包括&#xff1a;内存管理、进程管理…

【基础算法】二分(二分查找 + 二分答案)

文章目录 一、二分查找1. 【案例】在排序数组中查找元素的第一个和最后一个位置 ⭐(1) 二分查找的引入(2) 解题细节&#xff08;important&#xff09;(3) 代码示例(4) 【模板】二分查找(5) STL 中的二分查找 2. 牛可乐和封印魔法 ⭐⭐(1) 解题思路(2) 代码实现 3. A-B 数对 ⭐…