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

类锁和实例对象锁你分清了吗?

系列文章目录

文章目录

  • 系列文章目录
  • 前言
  • 一、什么是锁竞争?
  • 二、什么是类锁?什么是实例对象锁?
  • 三、给类对象加锁不是锁住了整个类
  • 四、总结


前言

java选手们应该都对锁不陌生,加锁了就是为保证操作语句的原子性,如果你是刚学并发编程,是否傻傻分不清楚对象锁和类锁呢?别怕!!!你看到了我的这篇文章就能帮你解决这个困惑~~


一、什么是锁竞争?

当我们使用synchronized个一个对象加上了锁,多个线程尝试在自己的内存空间上拿到这个加了锁的对象时,此时就会发生锁竞争,在竞争的瞬间只有一个线程可以拿到这个加了锁的对象,此时线程就是安全的。
举个例子:

假设你寝室里的卫生间只有一个马桶,某天晚上,你室友们同时都想去上厕所,那么你们就是要去抢这个厕所。
在这里你和你的室友就是线程;
厕所里的马桶就是对象;
厕所门上的锁就是synchronized;

二、什么是类锁?什么是实例对象锁?

类锁就是对类的成员或者方法或者类对象加锁,类锁本质就是对类对象加锁。

什么是类对象?
类对象就是.class对象,类对象详细的记录了程序员在定义这个类时全部的信息,比如:属性、方法等
你可以看到类对象是.class,类对象来源与.class文件,.class文件是由javac编译器根据.java源文件编译出来的,你可以理解成源文件只有一份,所以类对象也只有一份

类锁:
给static修饰的属性或者方法或者直接在synchronized(类.class)都是在给类加锁
实例对象锁:
给非static修饰的属性或者方法加锁

//给count加2000次
class A{static int count;//对静态方法加锁,就是对类对象加锁static synchronized void fun1(){for (int i = 0; i < 10000; i++) {count++;}System.out.println("我是类方法"+count);}//对实例方法加锁,就是对实例对象加锁synchronized void  fun2(){for (int i = 0; i < 10000; i++) {count++;}System.out.println("我是实例方法"+count);}
}

三、给类对象加锁不是锁住了整个类

是否线程安全,就看两个线程是否是针尝试获取到同一个加了锁的对象。就算里给类对象加了锁,也不是意味着一个线程拿到锁了,其他线程只能阻塞等待,如果其他线程本来就没有要去获取到这把类锁,而是去获取到实例对象的锁,那么这里就不存在多个线程竞争获取同一个对象竞争同一把锁。

看下面这段代码:

//线程不安全,t1和t2尝试获取的是两个不同的对象,一个是类对象,一个是实例对象,获取的不是同一把锁,不存在锁冲突
public class Test {public static void main(String[] args) throws InterruptedException {A a = new A();//线程1获取到是static修饰的方法Thread t1 = new Thread(()->{A.fun1();try {Thread.sleep(10000);} catch (InterruptedException e) {e.printStackTrace();}});//线程2获取到的是非static修饰的方法Thread t2 = new Thread(()->{a.fun2();});t1.start();t2.start();t1.join();t2.join();}}
class A{static int count;//对静态方法加锁,就是对类对象加锁static synchronized void fun1(){for (int i = 0; i < 10000; i++) {count++;}System.out.println("我是类方法"+count);}//对实例方法加锁,就是对实例对象加锁synchronized void  fun2(){for (int i = 0; i < 10000; i++) {count++;}System.out.println("我是实例方法"+count);}
}

线程不安全,结果小于20000:
在这里插入图片描述

下面两段代码,多个线程就是在尝试获取同一锁
看下面这段代码:
t1、t2尝试获取同一把锁,实例对象锁

//t1和t2尝试获取到同一把锁,
public class Test {public static void main(String[] args) throws InterruptedException {A a = new A();//线程1获取到是非static修饰的方法Thread t1 = new Thread(()->{
//           A.fun1();a.fun2();});//线程2获取到的是非static修饰的方法Thread t2 = new Thread(()->{a.fun2();
//            A.fun1();});t1.start();t2.start();t1.join();t2.join();}}
class A{static int count;//对静态方法加锁,就是对类对象加锁static synchronized void fun1(){for (int i = 0; i < 10000; i++) {count++;}System.out.println("我是类方法"+count);}//对实例方法加锁,就是对实例对象加锁synchronized void  fun2(){for (int i = 0; i < 10000; i++) {count++;}System.out.println("我是实例方法"+count);}
}

看下面一段代码:
t1和t2尝试获取到同一把类锁

public class Test {public static void main(String[] args) throws InterruptedException {A a = new A();//线程1获取到是static修饰的方法Thread t1 = new Thread(()->{A.fun1();
//            a.fun2();});//线程2获取到的是static修饰的方法Thread t2 = new Thread(()->{
//           a.fun2();A.fun1();});t1.start();t2.start();t1.join();t2.join();}}
class A{static int count;//对静态方法加锁,就是对类对象加锁static synchronized void fun1(){for (int i = 0; i < 10000; i++) {count++;}System.out.println("我是类方法"+count);}//对实例方法加锁,就是对实例对象加锁synchronized void  fun2(){for (int i = 0; i < 10000; i++) {count++;}System.out.println("我是实例方法"+count);}
}

四、总结

多线安全是否安全和不单单只是看synchronized修饰的属性,因为java里的任何对象都可以被synchronized修饰,关键在于多个线程是否是尝试获取相同的锁对象,如果是同一把锁就会发送锁冲突,线程安全。否则就不存在锁冲突,线程不安全。
所以不要被类锁和对象锁的名称给迷晕了,就看多个线程是否是在获取同一把锁,如果是同一个实例对象锁,线程安全;如果是同一个类对象锁,线程安全;如果是一个线程获取类锁,一个线程获取实例对象锁,不安全。

相关文章:

类锁和实例对象锁你分清了吗?

系列文章目录 文章目录 系列文章目录前言一、什么是锁竞争&#xff1f;二、什么是类锁&#xff1f;什么是实例对象锁&#xff1f;三、给类对象加锁不是锁住了整个类四、总结 前言 java选手们应该都对锁不陌生&#xff0c;加锁了就是为保证操作语句的原子性&#xff0c;如果你是…...

如何在麒麟上安装 ONLYOFFICE 桌面编辑器

我们很高兴地告诉大家&#xff0c;ONLYOFFICE 桌面编辑器现已上架麒麟软件商店。请阅读下文了解详情。 关于麒麟 麒麟是一款国产操作系统&#xff0c;主要是为了满足中国市场的需求和偏好而设计的。 它能够与各种硬件平台和软件应用程序的广泛兼容&#xff0c;因而受到认可。…...

记录:如何编写linux驱动,用module的方式

记录:如何编写Linux驱动,用module的方式 记录:如何编写Linux驱动,用module的方式参考记录:如何编写Linux驱动,用module的方式 编写一个 Linux 的驱动,用 module 方式开发,一般来说,编写一个 Linux 的驱动,需要遵循以下步骤: 确定设备的类型和功能,以及它在系统中的…...

3款免费又好用的 Docker 可视化管理工具

前言 Docker提供了命令行工具&#xff08;Docker CLI&#xff09;来管理Docker容器、镜像、网络和数据卷等Docker组件。我们也可以使用可视化管理工具来更方便地查看和管理Docker容器、镜像、网络和数据卷等Docker组件。今天我们来介绍3款免费且好用的 Docker 可视化管理工具。…...

C语言--判断一个年份是否是闰年(详解)

一.闰年的定义 闰年是指在公历&#xff08;格里高利历&#xff09;中&#xff0c;年份可以被4整除但不能被100整除的年份&#xff0c;或者可以被400整除的年份。简单来说&#xff0c;闰年是一个比平年多出一天的年份&#xff0c;即2月有29天。闰年的目的是校准公历与地球公转周…...

Python---排序算法

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 Python中的排序算法用于对数据进行排序。排序算法可以使数据按照一定的规则进行排列&#xff0c;以便于数据的查找、统计、比较等操作。在数据分析、机器学习、图形计算等领域&#xff0c…...

gitlab Blocking and unblocking users

原文&#xff1a;Redirecting... Blocking a userUnblocking a user Blocking and unblocking users GitLab 管理员阻止和取消阻止用户. Blocking a user 为了完全阻止用户访问 GitLab 实例&#xff0c;管理员可以选择阻止该用户. 可以通过滥用报告或直接从管理区域来阻止…...

Swift 和 Python 两种语言中带关联信息错误(异常)类型的比较

0. 概览 如果我们分别在平静如水、和谐感人的 Swift 和 Python 社区抛出诸如“Python 是天下最好的语言…” 和 “Swift 是宇宙第一语言…”之类的言论会有怎样的“下场”&#xff1f; 我们并不想对可能发生的“炸裂”景象做出什么预测&#xff0c;也无意比较 Swift 与 Pytho…...

北京联通iptv组播配置

多年前折腾过iptv&#xff0c;近期搬家换了个大电视&#xff0c;打算把iptv配置好了&#xff0c;尽管不怎么看&#xff0c;但聊胜于无。 其实很简单&#xff0c;用到了一些工具&#xff0c;记录如下 1. openwrt配置 因为有软路由&#xff0c;所以就借助openwrt了&#xff0c;一…...

C++ STL 迭代器失效

一、学习资料 STL迭代器的使用 二、vector容器获取值是下标法和at()的区别 vector<int> vA; int array[]{0,1,2,3,4}; vA.assign(array,array5); cout<<vA[6]<<endl; cout<<va.at(6)<<endl;如上述代码&#xff0c;当使用vA[6]的方式出现访问越…...

麒麟KYLINIOS软件仓库搭建02-软件仓库添加新的软件包

原文链接&#xff1a;麒麟KYLINIOS软件仓库搭建02-软件仓库添加新的软件包 hello&#xff0c;大家好啊&#xff0c;今天给大家带来麒麟桌面操作系统软件仓库搭建的文章02-软件仓库添加新的软件包&#xff0c;本篇文章主要给大家介绍了如何在麒麟桌面操作系统2203-x86版本上&…...

专业媒体播放软件Movist Pro中文

Movist Pro是一款专为Mac用户设计的专业媒体播放器。它支持广泛的视频和音频格式&#xff0c;包括MP4、AVI、MKV等&#xff0c;并提供了高级播放控件和定制的视频设置。其直观易用的用户界面&#xff0c;使得播放高清视频更为流畅&#xff0c;且不会卡顿或滞后。同时&#xff0…...

数据结构-邻接表广度优先搜索(C语言版)

对于一个有向图无向图&#xff0c;我们下面介绍第二种遍历方式。 广度优先搜索&#xff0c;即优先对同一层的顶点进行遍历。 如下图所示&#xff1a; 该例子&#xff0c;我们有六个顶点&#xff0c; 十条边。 对于广度优先搜索&#xff0c;我们先搜索a&#xff0c;再搜索abc…...

Py之auto-gptq:auto-gptq的简介、安装、使用方法之详细攻略

Py之auto-gptq&#xff1a;auto-gptq的简介、安装、使用方法之详细攻略 目录 auto-gptq的简介 1、版本更新历史 2、性能对比 推理速度 困惑度&#xff08;PPL&#xff09; 3、支持的模型 3、支持的评估任务 auto-gptq的安装 auto-gptq的使用方法 1、基础用法 (1)、量…...

【Linux】Linux+Nginx部署项目(负载均衡动静分离)

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于Linux的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.Nginx负载均衡 1.什么是负载均衡 2.实…...

C++笔记之vector的成员函数swap()和data()

C笔记之vector的成员函数swap()和data() 标准C中的std::vector类确实有swap()和data()这两个成员函数。下面是它们的简要描述&#xff1a; swap(): std::vector的swap()成员函数用于交换两个向量的内容&#xff0c;实现了高效的交换操作&#xff0c;不需要复制向量的元素。这…...

Linux centos环境 安装谷歌浏览器

教程 地址...

go-gin-vue3-elementPlus带参手动上传文件

文章目录 一. 总体代码流程1.1 全局Axios部分样例1.2 上传业务 二. 后端部分三. 测试样例 go的mvc层使用gin框架. 总的来说gin的formFile封装的不如springboot的好.获取值有很多的坑. 当然使用axios的formData也有不少坑.现给出较好的解决办法 以下部分仅贴出关键代码 一. 总…...

艺术的维度:洞察AI诈骗,优雅防范之艺术

当前&#xff0c;AI技术的广泛应用为社会公众提供了个性化智能化的信息服务&#xff0c;也给网络诈骗带来可乘之机&#xff0c;如不法分子通过面部替换语音合成等方式制作虚假图像、音频、视频仿冒他人身份实施诈骗、侵害消费者合法权益。 以下是一些常见的AI诈骗例子&#xf…...

JavaScript的作用域和作用域链

作用域 ● 作用域&#xff08;Scoping&#xff09;&#xff1a;我们程序中变量的组织和访问方式。"变量存在在哪里&#xff1f;“或者"我们可以在哪里访问某个变量&#xff0c;以及在哪里不能访问&#xff1f;” ● 词法作用域&#xff08;Lexical scoping&#xff…...

Spring Cloud AWS 实战教程:构建高可用 SQS 消息队列应用 [特殊字符]

Spring Cloud AWS 实战教程&#xff1a;构建高可用 SQS 消息队列应用 &#x1f680; 【免费下载链接】spring-cloud-aws The New Home for Spring Cloud AWS 项目地址: https://gitcode.com/gh_mirrors/sp/spring-cloud-aws Spring Cloud AWS 是一个强大的开源框架&…...

Android 11开发避坑:为什么你的App获取的Wifi MAC地址总是变?手把手教你配置固定MAC

Android 11开发实战&#xff1a;彻底解决Wifi MAC地址随机化问题最近在开发一个设备管理系统时&#xff0c;遇到了一个棘手的问题&#xff1a;我们的App在Android 11设备上获取的Wifi MAC地址每次都不一样&#xff0c;导致基于MAC地址的设备识别功能完全失效。经过一周的深入研…...

【DeepSeek测试用例生成实战指南】:20年QA专家亲授5大高覆盖率生成模式与3个避坑红线

更多请点击&#xff1a; https://codechina.net 第一章&#xff1a;DeepSeek测试用例生成的核心价值与适用边界 DeepSeek系列大模型在代码理解与生成任务中展现出显著的上下文建模能力&#xff0c;其测试用例生成功能并非通用“黑盒测试器”&#xff0c;而是聚焦于**单元级、函…...

Agent开发面试通关攻略:吃透稳拿offer

阅读前置&#xff1a;2026年当下最卷也最缺人的AI岗位&#xff0c;一定是AI Agent开发。最近刷遍CSDN、牛客、力扣最新面经&#xff0c;发现一个非常明显的招聘趋势&#xff1a;普通大模型微调岗位饱和内卷&#xff0c;而AI Agent开发岗位人才严重缺口&#xff0c;薪资更高、竞…...

别被忽悠了!2026亲测靠谱的AI论文网站|避坑精选版

2026 年学术写作工具已高度分化&#xff0c;千笔AI与ThouPen为全流程首选&#xff0c;豆包、DeepSeek 为专项强手&#xff1b;避坑关键&#xff1a;拒绝假文献、严控 AIGC 率、优先国内适配、免费试用先行。 一、TOP3 全流程首选&#xff08;亲测不踩雷&#xff09; 1. 千笔AI&…...

Postgresql基础实践教程(八)

⭐️⭐️⭐️⭐️⭐️ 完整数据详见 练习数据免费 ⭐️⭐️⭐️⭐️⭐️ 六十九、查找会员ID 27的向上推荐链 问题 查找会员ID 27的向上推荐链&#xff1a;即推荐该会员的人&#xff0c;以及推荐那个人的人&#xff0c;依此类推。返回会员ID、名字和姓氏。按会员ID降序排列。…...

C++ vector容器总结

vector基本概念功能&#xff1a;vector数据结构和数组非常相似&#xff0c;也称为单端数组vector与普通数组区别&#xff1a;不同之处在于数组是静态空间&#xff0c;而vector可以动态扩展动态扩展&#xff1a;并不是在原空间之后续接新空间&#xff0c;而是找更大的内存空间&a…...

Unity项目DrawCall降不下来?试试用Mesh Baker合并贴图集,保姆级图文教程

Unity性能优化实战&#xff1a;用Mesh Baker合并贴图集降低DrawCall全流程解析当你的Unity项目帧率开始卡顿&#xff0c;Profiler里DrawCall数字居高不下时&#xff0c;合并贴图集往往是解决问题的关键一步。本文将以一个实际项目为例&#xff0c;带你从零开始使用Mesh Baker的…...

CentOS 8.5最小化安装后,这5个必做的安全与效率优化设置(附一键脚本)

CentOS 8.5最小化安装后的5个必做安全与效率优化刚完成CentOS 8.5最小化安装的系统就像一张白纸——干净但缺乏生产力。作为运维老手&#xff0c;我见过太多人跳过基础优化直接部署应用&#xff0c;结果在后续使用中频繁遇到权限混乱、软件安装慢、SSH爆破等问题。本文将分享我…...

操作符从浅入深的讲解

1. 操作符的分类 2. ⼆进制和进制转换 3. 原码、反码、补码 4. 移位操作符 5. 位操作符&#xff1a;&、|、^、~ 6. 单⽬操作符 7. 逗号表达式 8. 下标访问[]、函数调⽤() 9. 结构成员访问操作符 10. 操作符的属性&#xff1a;优先级、结合性 11. 表达式求值1.操作符的分类以…...