JavaEE: 线程安全问题的解决方案(synchronized)

news2025/1/10 22:31:08

发生原因

要想解决线程安全问题,那么我们首先得知道线程安全问题为什么会发生.

发生原因:

  1. 线程在操作系统中是"随机调度,抢占式执行的"[根本原因].
  2. 多个线程,同时修改同一个变量
  3. 修改操作不是"原子"的
  4. 内存可见性问题
  5. 指令重排序

解决方案

原因1和2,我们很难去改变.本文主要介绍3 . 4 , 5 后面再说.

解决线程安全问题,最主要的办法就是把"非原子"的修改,变成"原子".也就是 ---- 加锁.
此处的加锁并不是真的让 count++ 变成原子的,也没有干预到线程的调度,只不过是通过这种加锁的方式,使一个线程在执行count++的过程中,其他的线程的count++不能插队进来~

synchronized关键字

Java中提供了synchronized关键字来完成加锁操作.

synchronized ()

synchronized ( ) 是关键字,不是函数,后面的()并非是参数,而是"锁对象". ( )里的对象可以指定任何的对象.
在这里插入图片描述

public class Demo9 {
	//锁对象
    private static Object locker = new Object();
    
    private static int count = 0;
    
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 50000; i++) {
            	//加锁
                synchronized (locker) {
                    count++;
                }
            }
        });
        Thread t2 = new Thread(()->{
            for(int i = 0; i < 50000;i++) {
            	//加锁
                synchronized (locker) {
                    count++;
                }
            }
        });

		//创建线程
        t1.start();
        t2.start();

		//让main线程等待t1和t2
        t1.join();
        t2.join();

        System.out.println(count);
    }
}

在这里插入图片描述
上述代码有效的前提是,两个线程都加锁了,而且是针对同一个对象加锁了!!!

锁对象的作用就是来区分两个线程是否是针对"同一个对象"加锁.

  • 是针对同一个对象加锁,此时就会出现"阻塞"(锁竞争 / 锁冲突)
  • 不是针对同一个对象加锁,此时不会出现"阻塞",两个线程仍然是随机调度的并发执行.
  • 锁对象,填哪个对象不重要,重要的是,多个线程是否是同一个对象~

刚才看到的情况是两个线程,针对一个锁加锁的,如果是多线程呢?

如果是3个线程针对同一个对象加锁~

也是类似的情况
其中某个线程先加上锁,另外两个线程阻塞等待,(哪个线程拿到锁,这个过程是不可预期的)

拿到锁的线程释放了锁之后,剩下的两个线程谁先拿到锁呢? 也是顺序不确定的!

1 2 3
比如最开始 1 拿到锁, 2 3 阻塞等待
1释放锁之后,2 和 3 谁先拿到锁? 不一定! 也是随机的,即使 2 先加锁,3后加锁,也不一定谁先拿到~


此处的 synchronized 是JVM 提供的功能,synchronized 底层实现就是JVM中通过C++代码来实现的
进一步的,也是依靠操作系统的 api 实现的加锁, 操作系统的 api 则是来自于cpu上支持的特殊的指令来实现的~
在这里插入图片描述

c++ / Python 加锁是一个函数,解锁是一个函数
像Java这种通过 synchronized 关键字,来同时完成加锁解锁,是比较少见的


synchronized 还可以修饰一个方法

synchronized 修饰普通的方法:

public void add() {
	synchronized (this) {
		count++;
	}
}

等价于

// 针对这个写法,锁对象就是this
synchronized public void add() {
	count++;
}

synchronized 修饰static方法:

class Counter {
	public static void func() {
		synchronized (Counter.class) {
		}
	}
}

等价于

class Counter {
	synchronized public static void func() {
	}
}

并非是写了synchronized 就一定线程安全,还是要看代码具体咋写~

换而言之,到底是否要加synchronized,怎么加锁,都是和具体的场景直接相关的

像上面那种"无脑加锁"的做法是不推荐的
使用锁是需要付出代价的(性能),使用锁就可能触发阻塞,一旦某个线程阻塞,啥时候能恢复阻塞,继续执行,是不可预期的(可能要非常多时间)

总结一下

synchronized 几种使用方式:

  1. synchronized ( ) { }
    圆括号指定锁对象
  2. synchronized 修饰一个普通的方法
    相当于针对 this 加锁
  3. synchronized 修饰一个静态的方法
    相当于针对 对应的类对象 加锁

锁对象:

  1. 可以吧任意的 Object / Object 子类的对象,作为锁对象
  2. 锁对象是啥不重要,重要的是,两个线程的锁对象是否是同一个
    • 是同一个,才会出现 阻塞 / 锁竞争
    • 不是同一个,不会出现 阻塞 / 锁竞争

本文到这里就结束啦~

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

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

相关文章

基于YOLOv8的茶叶病变检测系统

基于YOLOv8的茶叶病变检测系统 (价格85) 包含 [Algal Leaf Spot, Brown Blight, Gray Blight, Healthy, Helopeltis, Red Leaf Spot] 6个类 翻译&#xff1a; [藻类叶斑病&#xff0c;褐疫病&#xff0c;灰疫病&#xff0c;健康&#xff0c;茶角盲蝽&#xff0c; 红叶斑…

08.SQL注入-下(超详细!!!)

1、Access注入 1.1 判断是否存在注入漏洞 ?id10 and 11 //不报错 ?id10 and 12 //报错1.2 判断字段数 ?id10 order by 1 ... ?id10 order by 7 //不报错 ?id10 order by 8 //报错 说明有7个字段1.3 猜表名 ?id10 and exists(select * from administrator) …

IP协议解析

我最近开了几个专栏&#xff0c;诚信互三&#xff01; > |||《算法专栏》&#xff1a;&#xff1a;刷题教程来自网站《代码随想录》。||| > |||《C专栏》&#xff1a;&#xff1a;记录我学习C的经历&#xff0c;看完你一定会有收获。||| > |||《Linux专栏》&#xff1…

C语言宏定义的使用

文章目录 &#x1f34a;自我介绍&#x1f34a;宏定义&#x1f34a;宏函数&#x1f34a;嵌入式开发常用do...while(0)&#x1f34a;字符串化运算符 ‘ # ’&#x1f34a;不定参数宏 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以&#xff1a;点赞关注评论收藏&#xf…

SQL报错注入之floor

目录 1.简述 2.关键函数说明 1.rand函数 2.floor&#xff08;rand&#xff08;0&#xff09;*2&#xff09;函数 3.group by 函数 4.count&#xff08;*&#xff09;函数 3.报错分析 4.报错流程 4.1寻找注入点 4.2爆数据库名 4.3爆表名 4.4爆字段名 4.5查询数据 1.…

32、Python之面向对象:对象的表示,再论Python是dict包括语法糖

引言 在前面介绍Python容器的时候&#xff0c;我们曾经用过这种夸张的表述&#xff0c;“Python就是包裹在一堆语法糖中的字典”。虽然夸张&#xff0c;其实更多的是为了突出Python中dict的强大之处。今天这篇文章&#xff0c;打算看下Python中类对象、实例对象的表示及内存管理…

甄选范文“论负载均衡技术在Web系统中的应用”软考高级论文系统架构设计师论文

论文真题 负载均衡技术是提升Web系统性能的重要方法。利用负载均衡技术, 可将负载(工作任务) 进行平衡、分摊到多个操作单元上执行, 从而协同完成工作任务, 达到提升Web系统性能的目的。 请围绕“负载均衡技术在Web系统中的应用”论题, 依次从以下三个方面进行论述。 1.…

自动化测试 — selenium + Java

什么是自动化测试 将人为驱动的测试行为转化为机器执行的过程。 自动化测试包括UI 自动化&#xff0c;接口自动化&#xff0c;单元测试自动化。按照这个金字塔模型来进行自动化测试规划&#xff0c;可以产生最佳的自贡话测试产出投入比&#xff08;ROI &#xff09;&#xff0c…

智能氮气柜如何为存储应用提供稳定和安全的环境?

智能氮气柜在保持内部环境的严格控制下&#xff0c;如何为各类高要求的存储应用提供一个稳定和安全的环境&#xff1f; 智能氮气柜内部安装高精度温湿度传感器&#xff0c;持续监测内部环境状况。通过外部连接的氮气供应源&#xff0c;向柜内注入高纯度氮气&#xff0c;当检测到…

k8s—ingress应用

一、ingress和ingress-controller ingress对象&#xff1a; 指的是k8s中的⼀个api对象/资源对象&#xff0c;⼀般⽤yaml配置。作⽤是定义请求如何转发到service的规则&#xff0c;可以理解为配置模板。 ingress-controller&#xff1a; 具体实现反向代理及负载均衡的程序&…

IO-Link通信笔记(十七)——可任意MCU平台移植的面向对象程序设计的IO-Link从站协议栈与接口代码生成和监控上位机与便携式通信主站

一、可任意MCU平台移植的面向对象程序设计的IO-Link从站协议栈 图形化界面与驱动代码库生成功能&#xff0c;是现如今几大半导体芯片供应商选择向广大开发人员推荐的主流开发方式&#xff0c;例如意法的cube-mx。开发人员可以通过这些软件针对所使用芯片的相关外设资源&#xf…

缺失值处理方法:代数/统计/机器学习算法补全数据(附Python-sklearn代码精美可视化绘图)

注&#xff1a;本期的删除或插补方法主要针对连续数据&#xff0c;时间序列数据的插补在后续关于时间序列的博客中讲明。参考鸢尾花丛书&#xff0c;链接如下&#xff1a; 参考书籍及源代码链接https://github.com/Visualize-ML 博客是选出自己感觉用的到的精炼部分加自己的理…

春秋云境 | 文件上传 | CVE-2022-30887

目录 靶标介绍 开启靶场 上传一句话木马 蚁剑连接 找到 flag 靶标介绍 多语言药房管理系统 (MPMS) 是用 PHP 和 MySQL 开发的, 该软件的主要目的是在药房和客户之间提供一套接口&#xff0c;客户是该软件的主要用户。该软件有助于为药房业务创建一个综合数据库&#xff0…

eclipse无法使用jdk1.6编译老项目

主要修改两个地方的配置&#xff1a; 1、eclipse中配置的maven版本不能过高&#xff0c;亲测3.2.5版本是好使的。 2、修改eclipse安装目录下的eclipse.ini文件&#xff0c;将其中的-Dosgi.requiredJavaVersion更改为1.6即可&#xff0c;我得默认是1.7 最后附上maven安装包&…

AGV一体式ARM智能控制主机如何替代传统PLC、工控机等方案

工业自动化的不断发展&#xff0c;AGV&#xff08;自动导引车&#xff09;作为一种重要的物流搬运设备&#xff0c;在各个领域得到了广泛的应用。而 AGV 的控制主机是其核心部件之一&#xff0c;直接影响着 AGV 的性能和稳定性。传统的 AGV 控制主机通常采用 x86 工控机交换机i…

【密码学】密码协议的分类:②认证协议

密码协议的分类有很多种方式&#xff0c;这里我采取的是基于协议实现的目的来分类。可以将密码协议分成三类&#xff1a;认证协议、密钥建立协议、认证密钥建立协议。 一、认证协议是什么&#xff1f; 认证协议都在认证些什么东西呢&#xff1f;认证一般要认证三个东西&#x…

防止老年痴呆的小学题

直角三角形的周长为16,斜边长为7,求三角形的面积(不使用勾股定理) 答案为(9*9-7*7)/4

aria2下载器在windows端的使用

一、下载aria2 aria2aria2 is a lightweight multi-protocol & multi-source command-linedownload utility. It supports HTTP/HTTPS, FTP, SFTP,BitTorrent and Metalink. …https://aria2.github.io/打开链接&#xff0c;点击要下载的版本&#xff0c;注意windows版本跟…

k8s持久化存储PV和PVC

一、PV和PVC 1.PersistentVolume (PV) PersistentVolume (PV) 是外部存储系统中的⼀块存储空间&#xff0c;由管理员创建和维护。与 Volume⼀样&#xff0c; PV 具有持久性&#xff0c;⽣命周期独⽴于 Pod&#xff1b; 2.PersistentVolumeClaim (PVC) PersistentVolumeClaim…

MySQL的三大关键日志:Bin Log、Redo Log与Undo Log

MySQL的三大关键日志&#xff1a;Bin Log、Redo Log与Undo Log 1. Bin Log&#xff08;二进制日志&#xff09;2. Redo Log&#xff08;重做日志&#xff09;3. Undo Log&#xff08;回滚日志&#xff09; ) &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷…