synchronized关键字最主要有以下3种应用方式:
1、乐观锁和悲观锁
乐观锁:乐观锁在处理一段代码时,它会乐观的认为读多写少,也就是并发执行的情况概率很低,代码都是串行执行的,他认为每次去拿数据时,别人都不会对数据进行修改,而只有当写数据时才会正式对数据上锁,它会先去获取一下版本号,看一下版本号有没有发生改变,如果发生改变,就会重复读–比较–写的操作(CAS操作),Java中的乐观锁一般都是通过CAS操作实现的。
悲观锁:悲观锁和乐观锁是完全相反的,它会认为读少写多,并发执行的概率很高,它会认为他在读取数据之后还会有线程对数据做出修改,所以他会在读取数据时就会上锁,这样后面的线程就拿不到锁对象了,从而进入阻塞状态,直到获取到锁,这样做会涉及到线程状态的来回切换,代价较高,性能较低,Java中Synchronized就是一个悲观锁。
Synchronized 是一个悲观锁的实现,因为它假设任何时候都有可能发生竞争,因此在执行同步代码块前会先获得锁,并且如果获取不到锁就会一直等待。这样可以确保在同一时间只有一个线程可以访问共享资源,从而保证线程安全。但是这种做法会带来一定的性能损失,因为大部分时间锁并没有被竞争,但是所有线程都需要等待。
相比之下,乐观锁的实现原理是假设竞争很少发生,因此在执行同步代码块前不会先获得锁,而是直接执行操作。在更新共享资源时,先读取资源的版本号,然后进行更新操作。如果其他线程在此期间修改了共享资源,那么版本号就会发生变化,此时更新操作会失败。此时,当前线程可以选择放弃操作,也可以重新尝试更新操作。乐观锁的实现方式通常会比悲观锁更加高效,因为大部分时间不需要等待锁的释放。
CAS(Compare And Swap)是一种基于乐观锁实现的原子操作。它的原理是先比较共享资源的当前值和期望值是否相等,如果相等就使用新值替换当前值。CAS 操作可以保证原子性,因为在执行操作期间,如果共享资源的值发生变化,CAS 操作会失败,此时就会重新尝试操作,直到成功为止。
CAS 操作具有以下特性:
需要注意的是,CAS 操作虽然能够提高性能,但是也有一定的局限性,比如只能适用于单个共享变量的操作,不能适用于复合操作等场景。在使用 CAS 操作时需要根据实际场景进行取舍。
oldValue与newValue
oldValue:代表之前读到的资源对象的状态值
newValue:代表享要将资源对象的状态值更新后的值
“此时AB线程争抢着去修改资源对象的状态值,然后占用它”
设a抢到了时间片,
a 对比 对象状态值=0, oldValue=0
二者compare,结果相等,符合预期,则swap对象状态值为1
b 对比 对象状态值=1, oldValue=0。
二者compare,结果不等,抢占失败,放弃swap操作。
实际应用中b不放弃swap
实际应用,通常会让b进行自旋(不断第重试cas操作,且配置次数避免死循环)
内置锁synchronized
即synchronized关键字修饰的同步代码块,是一种互斥锁。
每个Java对象都可以用做一个实现同步的锁,这些锁被称为内置锁或监视器锁。
用法1:类方法用synchronized关键字修饰,和synchronized(this)一样,获取的是当前类对象的互斥锁。
class ClassB{
public synchronized void func1(){}
}
用法2:同步代码块,在任意对象上获取的是该对象的同步锁。
class ClassC{
public Object lockObj = new Object();
public void func1()
{
synchronized(lockObj){
}
}
}
参考文章:
乐观锁(CAS)和悲观锁(synchronized)的详细介绍_傻鱼爱编程的博客-CSDN博客
悲观锁(Synchronized)和乐观锁(CAS)_synchronized是悲观锁吗_wyplj_sir的博客-CSDN博客
何谓悲观锁与乐观锁_林中静月下仙的博客-CSDN博客
常见的锁策略和synchronized实现原理_悲观锁为什么是重量级的_卑微小小羊的博客-CSDN博客
乐观锁与悲观锁讲解,CAS、synchronized、锁升级、ReentrantLock、AQS_synchronized是悲观锁吗_ZZYSY~的博客-CSDN博客 大聪明教你学Java | 深入浅出聊乐观锁与悲观锁(synchronized 悲观锁)_不肯过江东丶的博客-CSDN博客 Java_小弟季义钦的博客-CSDN博客