锁和synchronized

synchronized 锁升级 锁升级是 Java 用来优化锁的机制。在无竞争的情况下,使用偏向锁和轻量级锁,以减少不必要的开销。一旦有线程竞争,锁会升级为重量级锁,保证线程安全,但会带来性能上的代价。这就是锁升级的基本概念,目的是在不同的竞争情况下,动态调整锁的类型,从而提供最佳的性能和线程安全性。 阅读详情

锁的常见概念

  • 互斥: 同一时刻只有一个线程执行
  • 临界区:一段需要互斥执行的代码
  • 细粒度锁: 用不同的锁对受保护资源进行精细化管理。 细粒度锁可以提高并行度,是性能优化的一个重要手段
  • 死锁 :一组互相竞争资源的线程因互相等待,导致“永久”阻塞的现象 。
synchronized
class  X{
	//修饰非静态方法
	synchronized void foo(){
 	   //临界区
	}
	//修饰静态方法
	synchronized static void bar(){
 	   //临界区
	}
	
	//修饰代码块
	Object obj = new Object();
	void baz(){
   		synchronized(obj){
        	//临界区
    	}
	}
}

Java编译器会在synchronized修饰的方法或代码块前后自动加上加锁lock()和解锁unlock(),这样做的好处就是加锁lock()和解锁unlock()一定 是成对出现的,毕竟忘记解锁unlock()可是个致命的Bug(意味着其他线程只能死等下去了)。

修饰静态方法:
//修饰静态方法是用当前类的字节码文件作为锁
class  X{
	//修饰静态方法
	synchronized(X.class) static void bar(){
 	   //临界区
	}
}
修饰非静态方法:
//修饰非静态方法是用当前对象作为锁
class  X{
	//修饰非静态方法
	synchronized(this) static void bar(){
 	   //临界区
	}
}

如何用一把锁保护多个资源

受保护资源和锁之间合理的关联关系应该是N:1的关系,也就是说可以用一把锁来保护多个资源,但是不能用多把锁来保护一个资源,

使用锁的正确姿势
依转账业务作为示例

示例一:

public class Account {
    /**
     *锁:保护账⼾余额
     */
    private	final	Object	balLock	= new Object();
    /**
     * 账⼾余额
     */
    private	Integer	balance;
   
    /**
     * 错误的做法
     * 非静态方法的锁是this, 
     * this这把锁可以保护自己的余额this.balance,保护不了别人的余额 target.balance
     * 
     */
   synchronized void transfer(Account target,int amt){
        if (this.balance > amt) {
            this.balance -= amt;
            target.balance  = amt;//这段代码会出现线程安全,要保证线程安全的话要使用同一个锁
        }
    }
}

示例二:

public class Account {
    /**
     *锁:保护账⼾余额
     */
    private	final	Object	balLock	= new Object();
    /**
     * 账⼾余额
     */
    private	Integer	balance;
   

    /**
     * 正确的做法,但是会导致整个转账系统的串行
     *
     * Account.class是所有Account对象共享的,
     * 而且这个对象是Java虚拟机在加载Account类的时候创建的,
     * 所以我们不用担心它的唯一性
     *
     * 这样还有个弊端:所有的转账都是串行了
     */
    void transfer2(Account target,int amt){
        synchronized(Account.class){
            if (this.balance > amt) {
                this.balance -= amt;
                target.balance  = amt;
            }
        }
    }
}

这样的话转账操作就成了串行的了,正常的逻辑应该只锁转入账号和被转入账户;不影响其他的转账操作。稍作改造:

示例三:

public class Account {
    /**
     *锁:保护账⼾余额
     */
    private	final Object lock;
    /**
     * 账⼾余额
     */
    private	Integer	balance;
   
    //私有化无参构造
    private Account(){}
    //设置一个传递lock的有参构造
    private Account(Object lock){
        this.lock = lock;
    }
    
    /**
     * 转账
     */
    void transfer(Account target,int amt){
        //此处检查所有对象共享锁
        synchronized(lock){
            if (this.balance > amt) {
                this.balance -= amt;
                target.balance  = amt;
            }
        }
    }
}

这个方法虽然能够解决问题,但是它要求创建Account对象的时候必须传入同一个对象,

还有就是传递对象过于麻烦,写法繁琐缺乏可行性。

示例四:

public class Account {
    
    /**
     * 账⼾余额
     */
    private	Integer	balance;
    
    /**
     * 转账
     */
    void transfer(Account target,int amt){
        //此处检查所有对象共享锁
        synchronized(Account.class){
            if (this.balance > amt) {
                this.balance -= amt;
                target.balance  = amt;
            }
        }
    }
}

用Account.class作为共享的锁,锁定的范围太大。 Account.class是所有Account对象共享的,而且这个对象是Java虚拟机在加载Account类的时候创建的,所以我们不用担心它的唯一性。使用Account.class作为共享的锁,我们就无需在创建Account对象时传入了。

这样新的问题就出来了虽然用Account.class作为互斥锁,来解决银行业务里面的转账问题,虽然这个方案不存在 并发问题,但是所有账户的转账操作都是串行的,例如账户A转账户B、账户C转账户D这两个转账操作现实 世界里是可以并行的,但是在这个方案里却被串行化了,这样的话,性能太差。所以如果考虑并发量这种方法也不行的

正确的写法是这样的(使用细粒度锁):

示例五:

public class Account {
    
    /**
     * 账⼾余额
     */
    private	Integer	balance;
    
    /**
     * 转账
     */
    void transfer(Account target,int amt){
        //锁定转出账户
        synchronized(this){
             //锁住转入账户
            synchronized(target){
                if (this.balance > amt) {
                    this.balance -= amt;
                    target.balance  = amt;
                }
            }
        }
    }
}

我们试想在古代,没有信息化,账户的存在形式真的就是一个账本,而且每个账户都有一个账本,这些账本 都统一存放在文件架上。银行柜员在给我们做**转账时,要去文件架上把转出账本和转入账本都拿到手,然后做转账。**这个柜员在拿账本的时候可能遇到以下三种情况:

  1. 文件架上恰好有转出账本和转入账本,那就同时拿走;
  2. 如果文件架上只有转出账本和转入账本之一,那这个柜员就先把文件架上有的账本拿到手,同时等着其 他柜员把另外一个账本送回来;
  3. ​ 转出账本和转入账本都没有,那这个柜员就等着两个账本都被送回来。
细粒度锁有可能会出现死锁
  • 死锁 :一组互相竞争资源的线程因互相等待,导致“永久”阻塞的现象 。
  • 两个线程彼此拿着对方的资源都不释放就会导致死锁,
  • 使用细粒度锁可能会导致死锁

如果有客户找柜员张三做个转账业务:账户 A转账户B 100元,此时另一个客户找柜员李四也做个转账业务:账户B转账户A 100元,于是张三和李四同时都去文件架上拿账本,这时候有可能凑巧张三拿到了账本A,李四拿到了账本B。张三拿到账本A后就等着 账本B(账本B已经被李四拿走),而李四拿到账本B后就等着账本A(账本A已经被张三拿走),他们要等 多久呢?他们会永远等待下去…因为张三不会把账本A送回去,李四也不会把账本B送回去。我们姑且称为死等吧。

如何避免死锁
  1. 互斥,共享资源X和Y只能被一个线程占用;
  2. 占有且等待,线程T1已经取得共享资源X,在等待共享资源Y的时候,不释放共享资源x;
  3. 不可抢占,其他线程不能强行抢占线程T1占有的资源;
  4. 循环等待,线程1等待线程T2占有的资源,线程T2等待线程T1占有的资源,就是循环等待。

只要破坏其中一个就可以避免死锁

等待-通知机制

用synchronized实现等待-通知机制

  • synchronized 配合wait(),notif(),notifyAll()这三个方法能够轻松实现.
  • wait(): 当前线程释放锁,进入阻塞状态
  • notif(),notifAll(): 通知阻塞的线程有可以继续执行,线程进入可执行状态
  • notif()是会随机地地通知等待队歹一个线程
  • notifyAll()会通知等待队列中的所有线程,建议使用notifAll()

wait与sleep区别:

sleep是Object的中的方法,wait是Thread中的方法

wait会释放锁,sleep不会释放锁

wait需要用notif唤醒,sleep设置时间,时间到了唤醒

wait无需捕获异常,而sleep需要

wait(): 当前线程进入阻塞

IIS - 会话cookie中缺少HttpOnly属性 不啰嗦,我们直接开始! 先进行常规设置 打开配置编辑器 选中图中节点,将httpOnlyCookies设置为true 然后。。。不起作用。。。 换种方式 通过配置出站规则getcookie添加HttpOnly 在Web.config中添加如下出站规则 <rewrite> <outboundRules> <rule name="Add HttpOnly"> <match serverVa. 阅读详情

相关推荐

开源LocalAI本地人工智能安装教程

LocalAI是一款能在本地运行的人工智能应用,它兼容了OpenAI API规范,它可以在普通的电脑运行,不需要GPU,也不需要联网,音频转录

2301_78652552的博客 3613

在springboot中使用synchronized锁失效的问题

最近在实现博客系统的markdown文章导入功能的时候,遇到了多并发的问题,主要是导入插件是element-plus提供的,然后进行批量上传的时候,实际上是同一时间发送多次上传请求,也就出现了多并发的情况。本以为使用synchronized就可以处理的,结果还是一个知识点!!! 相关代码 public MlogTags saveIfAbsent(@NotNull(message = "标签名称不能为空") String tagName) { //从数据库获取标签,判断标签是否存在,如果不存在就新

光滑的秃头 4824

电容式麦克风:从原理到实际电路波形解析

本文深入解析电容式麦克风的工作原理,从核心的振膜与背板结构、电荷锁定机制到场效应管放大器的作用。通过实物拆解与等效电路分析,阐明声音振动如何转换为电压信号,并指导如何用示波器实测波形,直观展现声电转换过程,适合电子爱好者和音频技术学习者。

Black的专栏 1080

Java并发04之synchronized

当一个线程想要获得锁对象时,就会发现锁对象的Mark Work并不是存储null、哈希码和分代年龄(无锁),也不是存储线程指针、Epoch和分代年龄(偏向锁),也不是存储指向某一线程的Lock Record,而是存储了一个指向一个Monitor对象的指针,那么这个线程就会知道当前锁是一个重量级锁。此时,线程就会跑到Monitor对象的EntryList中,等待获得锁。-XX:+UseBiasedLocking 开启偏向锁-XX:BiasedLockingStartupDelay=0 关闭偏向锁延迟。

solololo的博客 955

别再让COGI拖慢你的SAP接口!手把手教你配置BAPI_PRODORDCONF_CREATE_TT的同步货物移动

本文深入解析SAP生产订单报工接口中的COGI问题,通过BAPI_PRODORDCONF_CREATE_TT的同步配置实战,解决异步更新导致的性能瓶颈。文章详细介绍了增强点配置和性能验证,帮助用户彻底消除COGI堆积,提升接口效率。

weixin_29214691的博客 482

如何配置 OpenClaw 使用免费搜索工具:摆脱付费 API 限制

本文介绍了如何配置OpenClaw使用免费搜索工具来替代付费API。主要内容包括:1)启用内置的web_fetch工具直接获取网页内容;2)创建自定义脚本聚合免费AI资讯源;3)配置其他免费网络工具。文章详细说明了配置步骤,推荐了多个优质免费AI资讯网站,并分析了该方案的优劣势。这种配置方式完全免费且灵活,特别适合预算有限的用户,能够在不依赖付费API的情况下获取所需信息。

dongdeaiziji的专栏 9814

Spring Boot高并发 锁的使用方法

在高并发场景中(比如电商秒杀、抢票系统、转账交易),多个线程/用户会**同时操作同一共享资源**(如库存、账户余额、订单号)。如果不做控制,会导致数据错误(如库存超卖、余额负数)、业务逻辑混乱(如重复下单)。锁(Lock)是解决这类问题的核心工具之一。

奔跑的坏蜗牛 1751

Mamba SSM 实战:IMDb 文本分类 + Mamba-ssm 全流程

Mamba SSM 文本分类链路:IMDb 二分类 → MambaLMHeadModel (d_model=256, n_layer=8, d_state=16, exp2=2) → 末 token 分类头。5 epoch 达 89.2% 准确率 (与 BERT-base 持平), 但显存降低 44% (3.5GB vs 6.2GB)。建议序列长度 ≥ 1024 再选 Mamba, 短序列 (< 512) 用 BERT 更高效。扩展时注意d_state。

m0_71589036的博客 57

synchronized和Lock

转载自: http://blog.youkuaiyun.com/zhibuguonicuo/article/details/69389771 http://blog.youkuaiyun.com/chenssy/article/details/54883355 synchronized在Java中,最基本的互斥同步手段就是synchronized关键字。synchronized可以保证方法或者代码块在运行时,同一时刻只有

ZERO 489

STM32cubemx配置驱动DHT11模块

本篇文章将带大家学习使用DHT11湿温度模块,使用这个模块可以获取当前的温度和湿度数据。DHT11可以用于智能家居,蔬菜大棚等项目当中适用范围广。DHT11 是一种数字式温湿度传感器,由杜邦公司推出。它可以测量环境中的温度和湿度,并将测量结果以数字形式传输给微控制器或其他电子设备,适用于通过数字信号读取环境温湿度的应用场景。DHT11 传感器使用单总线数据交换协议,可以通过一个 I/O 引脚进行控制和数据传输。

m0_49476241的博客 5912

Serdes之什么是(CDR)?

光收发器和电收发器使用的是我们所说的串行数据通信。在这种通信方式中,数据位是按顺序一个接一个地传输的。光收发器和电收发器使用的是我们所说的串行数据通信。在这种通信方式中,数据位是按顺序一个接一个地传输的。目前市场上大多数收发器都没有专用的时钟输入,因此时钟恢复和数据重新定时等功能是在收发器外部(即在主板上)进行的。接收端则需要恢复时钟以采样串行线上的数据。为了实现这一点,接收端需要一个与输入数据频率大致相同的时钟。通过使参考时钟与输入数据信号的跳变相位对齐,可以生成一个恢复的时钟。这被称为时钟恢复。

叫好与叫座虽然不是对立面,但想在同一个作品中达到双重效果很难。 2389

[SpringBoot的@Async注解和关键字synchronized的使用]

SpringBoot的@Async的详细使用说明,带样例,以及关键字synchronized同步代码块的使用

虽千万人,吾往矣 6410

水声信号处理开源算法库最新进展

欢迎关注本专栏,一起探索新世界大家好,我是ZhuChunSHU。985院校硕士毕业,现担任算法研究员一职,热衷于深度学习算法研究与应用。曾获得阿里云天池比赛第三名,CCE比赛第五名,科大讯飞Q比赛第六名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法行业就业。希望和大家一起成长进步。今天继续我们的专栏分享!!!!!!!!!!!!!!!!!!!!水声信号处理是海洋科学与工程领域的核心组成部分,对于水下通信、目标探测、海洋环境监测以及生物声学研究至关重要。

u012133341的博客 1254

synchronized锁,ReentrantLock 锁

(如程序计数器、栈指针、通用寄存器值等)到内存(通常是内核栈),再加载内核态的上下文。这个过程涉及多次内存读写(内存速度比 CPU 寄存器慢 100 倍以上),且需要严格保证操作的原子性(避免数据错乱),硬件层面的指令执行成本很高。切换时,CPU 必须保存当前用户态的。

chaodddddd的博客 1482

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

synchronized的四种锁状态

在 Java 中,`synchronized` 关键字是一个非常重要的同步机制,用于确保在多线程环境下,同一时刻只有一个线程可以执行某个方法或代码块。本文将详细介绍 `synchronized` 关键字的使用、锁的类型、锁的升级过程以及锁的实现原理。

专注Java和MySQL领域知识分享 1983

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Synchronized锁、锁的四种状态、锁的升级(偏向锁,轻量级锁,重量级锁)

Synchronized【对象锁】采用互斤的方式让同一时刻至多只有一个线程能持有【对象锁】,其它线程再想获取这个【对象锁】时就会阻塞住。synchronized方法和synchronized块。

m0_64422133的博客 3648

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Synchronized锁升级

jdk1.8:无锁 -> 偏向锁 -> 轻量锁 -> 重量级锁jdk15:无锁 -> 偏向锁(默认不开启,耗费维护成本高) -> 轻量锁 -> 重量级锁。

deku_的博客 1094

ReenTrantLock和Synchronized锁

当一个线程第一次请求锁时,JVM 会记录该线程的 ID,并将锁标记为偏向锁。此后,若同一线程再次访问该锁,JVM 会直接认为该线程已经持有锁,从而避免加锁和解锁操作,提升性能。线程第一次请求锁时,JVM 将锁对象标记为偏向锁,并记录线程 ID。当相同线程再次访问该锁时,JVM 检查对象头中的线程 ID,若匹配,线程直接获取锁,无需再次加锁。如果其他线程争用锁,偏向锁会被撤销,锁将进入轻量级锁或重量级锁状态。:适用于没有竞争的单线程场景,可以显著提升性能。:轻量级锁通常是偏向锁升级后的结果。

fqlya的博客 633

synchronized锁总结

介绍synchronized的特性,使用,和锁机制,介绍各种类型的锁,死锁问题即如何解决。

weixin_41965831的博客 1216

synchronized锁升级

如果锁获取成功,直接替换Mark Word中的线程ID为B自己的ID(A → B),重新偏向于其他线程( 即将偏向锁交给其他线程,相当于当前线程" 被"释放了锁),该锁会保持偏向锁状态,A线程Over,B线程上位。如果锁获取失败,则偏向锁升级为轻量级锁,此时轻量级锁由原持有偏向锁的线程持有,继续执行其同步代码,而正在竞争的线程B会进入自旋等待获得该轻量级锁。(4). 假如线程A已经拿到锁,这时线程B又来抢该对象的锁,由于该对象的锁已经被线程A拿到,当前该锁已是偏向锁了。此时线程B操作中有两种情况。

weixin_50823701的博客 1986

Java之Synchronized与锁升级

锁升级的过程锁升级后,hashcode去哪儿了?● 各种锁优缺点、synchronized锁升级和实现原理。

qq_62592925的博客 1358

Synchronized锁的使用

本篇文章是关于并发编程中Synchronized锁的用法知识记录,由于篇幅原因,核心原理知识下篇记录

小威的博客 4234

synchronized及锁优化

1. synchronized是基于进入与退出监视器对象(Monitor)来实现的,每个java对象都有一个Monitor对象。 2. Monitor依赖于操作系统底层实现 3.开启偏向锁的情况下(默认是开启的),锁状态演化顺序为 偏向锁,轻量级锁,重量级锁 4. 锁的各种优化措施,是为了避免线程从用户态进入到内核态,从而提高效率

他叫阿来 1198

synchronized锁的5种状态

synchronized用的锁是存在java对象头中,上锁,改变的就是对象头。 synchronized锁有5种状态:无锁,偏向锁,轻量级锁,重量级锁,GC标志信息。 0.java应用启动的时候会有多个系统自带的线程执行synchronized代码块,必然会导致由偏向锁升级为轻量级锁,为了避免升级所带来额外的开销, 此时jvm会关闭偏向锁,直接使用轻量级锁,默认等待4秒后再开启偏向锁,可用...

jingzhi_f 2376

Synchronized实现原理和锁优化

Synchronized的三种用法 synchronized可以保证方法或者代码块在运行时,同一时刻只有一个方法可以进入到临界区,同时它还可以保证共享变量的内存可见性 Java中每一个对象都可以作为锁,这是synchronized实现同步的基础。 synchronized 常见的三种用法如下: 普通同步方法,锁是当前实例对象 静态同步方法,锁是当前类的class对象 同步方法...

lzf的博客 4016

Synchronized锁优化

文章目录Synchronized锁优化(1)引言(2)Java对象的内存布局(3)偏向锁(4)轻量级锁(5)重量级锁 Synchronized锁优化 (1)引言 在JDK1.5之前,synchronized的底层实现都是重量级的,借助操作系统底层实现,也称之为synchronized为重量级锁,在JDK1.5之后,对Synchronized进行了各种优化,实现的原理是锁升级的过程,有了偏向锁、轻量级锁和重量级锁的概念。 (2)Java对象的内存布局 在Java中,创建一个对象后,在JVM中,对象在内存

WYSCODER的博客 1327
上一篇: 并发编程三要素:原子性,有序性,可见性
下一篇: Lock和Condition(可重入锁)
刘彦青-Yannis
博客等级 码龄10年 1万+粉丝 234原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘彦青-Yannis

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值