Synchronized锁膨胀现象是如何产生的?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1893个文字,预计阅读时间需要8分钟。
一、在并发编程中,使用`synchronized`和锁机制可以简化线程间的同步操作。具体来说,通过`synchronized`关键字修饰的方法或代码块,确保在任意时刻只有一个线程能够执行这部分代码,从而实现线程间的同步。
二、当实例方法被`synchronized`修饰时,表示这个方法是线程安全的,同一时刻只有一个线程可以执行这个方法。下面是对其原理和锁升级过程的探讨:
1. 原理:`synchronized`方法通过监视器锁(Monitor)来实现同步。每个对象都有一个监视器锁,当线程调用`synchronized`方法时,它会尝试获取该对象的监视器锁。如果成功,则进入同步块执行;如果失败,则等待,直到锁被释放。
2. 锁升级过程: - 偏向锁:在锁未被任何线程获取之前,JVM会假设以后总是由同一个线程访问同步块或同步方法,因此使用偏向锁。这种锁的获取和释放不需要CAS操作。 - 轻量级锁:当一个线程进入同步块时,如果同步块没有被其他线程锁定,则会尝试将锁从偏向锁转换为轻量级锁。轻量级锁通过CAS操作来操作对象的锁标记来实现,无需暂停线程。 - 重量级锁:如果轻量级锁竞争激烈,则可能需要转换为重量级锁。此时,线程会在锁对象的监视器队列上等待,直到获得锁。
总结:使用`synchronized`和锁机制可以简化线程同步操作,但需要注意锁的升级过程和性能影响。
一、序言在并发编程中,synchronized锁因其使用简单,在线程间同步被广泛应用。下面对其原理及锁升级过程进行探究。
当实例方法被synchronized修饰时,通过当前实例调用此方法的所有线程共用一把锁,不同对象调用此方法线程间互不影响。
public class A {
public synchronized void func() {
}
}
当使用synchronized锁修饰实例方法,锁添加在当前类的实例上,有多少个实例可添加多少把锁。
2、修饰代码块修饰代码块比修饰方法颗粒度更小。当实例方法代码块被synchronized修饰时,通过当前实例调用此方法的所有线程共用一把锁,不同对象调用此方法线程间互不影响。
public class B {
public void func() {
synchronized (this) {
}
}
}
当使用synchronized锁修饰代码块,锁添加在当前类的实例上,有多少个实例可添加多少把锁。
3、修饰静态方法当静态方法被synchronized修饰时,整个JVM所有调用此方法的线程均受同一个锁的约束。
public class C {
public static synchronized void func() {
}
}
当使用synchronized锁修饰静态方法,锁添加在当前类的类对象上,最多添加一把锁。
三、锁的升级非必要不使用synchronized修饰静态方法
Java 8所使用的synchronized锁是经过优化后的,存在偏向锁、轻量级锁、重量级锁等状态。
线程间不存在锁的竞争行为,至多只有一个线程有获取锁的需求,常见场景为单线程程序。
判断是不是偏向锁的标识是查看调用此方法的线程是否有且仅有一个。
在多线程编程里,被锁修饰的方法仅被单一线程调用几乎不存在,因此偏向锁比较鸡肋:如果能够明确单一线程调用目标方法,使用无锁编程更为合适。
2、性能比较无锁与偏向锁的性能差异非常接近,几乎可以忽略不计。
(二)轻量级锁线程间存在锁的伪竞争行为,即同一时刻绝对不会存在两个线程申请获取锁,各线程尽管都有使用锁的需求,但是是交替使用锁。
当有两个及以上线程调用被锁修饰的方法时,那么至少能确定是轻量级锁。
2、性能比较轻量级锁由于同一时刻不存在两个线程互相竞争锁,因此不存在线程阻塞-唤醒的上下文切换,因此性能相对重量级锁要高很多。
线程间存在锁的实质性竞争行为,线程间都有获取锁的需求,但是时间不可交错,互斥锁的阻塞等待。
当能够肯定至少有两个及以上线程调用被锁修饰的方法时,线程调用方法是随机的,那么大概率是重量级锁。
2、性能比较重量级锁由于涉及到线程阻塞-唤醒的上下文切换,造成相比较与无锁状态,效率低很多。
四、其它内容 (一)锁的性质 1、公平性synchronized锁是非公平锁,没有FIFO队列机制保障竞争锁的线程一定有几率获得锁。
synchronized锁是可重入锁,可重入意味着嵌套调用不会产生死锁问题。
synchronized锁是一种悲观锁,通过加锁实现线程间同步。
(二)理解重量级锁在多线程环境下,如果使用synchronized锁,那么大概率会升级到重量级锁。偏向锁和轻量级锁非刻意为之,很难存在,更大的意义是对比帮助理解重量级锁的性能。
重量级锁尽管会对性能产生很大影响,但是依旧是解决线程间同步的有效手段。
1、选用锁的建议当被锁修饰的方法或者代码块执行时间较长时,选用基于线程阻塞-唤醒切换上下文的方式进行线程同步效率相对较高。
当被锁修饰的方法或者代码块执行时间较短时,应选用其它替代锁,比如自旋锁等。
在实际多线程场景开发中,synchronized锁大概率会升级到重量级锁,因其单向升级的特点,重量级状态的synchronized锁可能会对实际业务的并发产生不利影响,手动选用其它锁可能会更合适。
synchronized锁仅可用于解决同一进程内不同线程间同步,对于分布式项目跨进城线程同步依赖于分布式锁,synchronized锁更多的意义是理解锁的过程。
喜欢本文就一下,激励我持续创作。这个Github同样精彩,收到您的star我会很激动。本文归档在专题博客,视频讲解在B站。
本文共计1893个文字,预计阅读时间需要8分钟。
一、在并发编程中,使用`synchronized`和锁机制可以简化线程间的同步操作。具体来说,通过`synchronized`关键字修饰的方法或代码块,确保在任意时刻只有一个线程能够执行这部分代码,从而实现线程间的同步。
二、当实例方法被`synchronized`修饰时,表示这个方法是线程安全的,同一时刻只有一个线程可以执行这个方法。下面是对其原理和锁升级过程的探讨:
1. 原理:`synchronized`方法通过监视器锁(Monitor)来实现同步。每个对象都有一个监视器锁,当线程调用`synchronized`方法时,它会尝试获取该对象的监视器锁。如果成功,则进入同步块执行;如果失败,则等待,直到锁被释放。
2. 锁升级过程: - 偏向锁:在锁未被任何线程获取之前,JVM会假设以后总是由同一个线程访问同步块或同步方法,因此使用偏向锁。这种锁的获取和释放不需要CAS操作。 - 轻量级锁:当一个线程进入同步块时,如果同步块没有被其他线程锁定,则会尝试将锁从偏向锁转换为轻量级锁。轻量级锁通过CAS操作来操作对象的锁标记来实现,无需暂停线程。 - 重量级锁:如果轻量级锁竞争激烈,则可能需要转换为重量级锁。此时,线程会在锁对象的监视器队列上等待,直到获得锁。
总结:使用`synchronized`和锁机制可以简化线程同步操作,但需要注意锁的升级过程和性能影响。
一、序言在并发编程中,synchronized锁因其使用简单,在线程间同步被广泛应用。下面对其原理及锁升级过程进行探究。
当实例方法被synchronized修饰时,通过当前实例调用此方法的所有线程共用一把锁,不同对象调用此方法线程间互不影响。
public class A {
public synchronized void func() {
}
}
当使用synchronized锁修饰实例方法,锁添加在当前类的实例上,有多少个实例可添加多少把锁。
2、修饰代码块修饰代码块比修饰方法颗粒度更小。当实例方法代码块被synchronized修饰时,通过当前实例调用此方法的所有线程共用一把锁,不同对象调用此方法线程间互不影响。
public class B {
public void func() {
synchronized (this) {
}
}
}
当使用synchronized锁修饰代码块,锁添加在当前类的实例上,有多少个实例可添加多少把锁。
3、修饰静态方法当静态方法被synchronized修饰时,整个JVM所有调用此方法的线程均受同一个锁的约束。
public class C {
public static synchronized void func() {
}
}
当使用synchronized锁修饰静态方法,锁添加在当前类的类对象上,最多添加一把锁。
三、锁的升级非必要不使用synchronized修饰静态方法
Java 8所使用的synchronized锁是经过优化后的,存在偏向锁、轻量级锁、重量级锁等状态。
线程间不存在锁的竞争行为,至多只有一个线程有获取锁的需求,常见场景为单线程程序。
判断是不是偏向锁的标识是查看调用此方法的线程是否有且仅有一个。
在多线程编程里,被锁修饰的方法仅被单一线程调用几乎不存在,因此偏向锁比较鸡肋:如果能够明确单一线程调用目标方法,使用无锁编程更为合适。
2、性能比较无锁与偏向锁的性能差异非常接近,几乎可以忽略不计。
(二)轻量级锁线程间存在锁的伪竞争行为,即同一时刻绝对不会存在两个线程申请获取锁,各线程尽管都有使用锁的需求,但是是交替使用锁。
当有两个及以上线程调用被锁修饰的方法时,那么至少能确定是轻量级锁。
2、性能比较轻量级锁由于同一时刻不存在两个线程互相竞争锁,因此不存在线程阻塞-唤醒的上下文切换,因此性能相对重量级锁要高很多。
线程间存在锁的实质性竞争行为,线程间都有获取锁的需求,但是时间不可交错,互斥锁的阻塞等待。
当能够肯定至少有两个及以上线程调用被锁修饰的方法时,线程调用方法是随机的,那么大概率是重量级锁。
2、性能比较重量级锁由于涉及到线程阻塞-唤醒的上下文切换,造成相比较与无锁状态,效率低很多。
四、其它内容 (一)锁的性质 1、公平性synchronized锁是非公平锁,没有FIFO队列机制保障竞争锁的线程一定有几率获得锁。
synchronized锁是可重入锁,可重入意味着嵌套调用不会产生死锁问题。
synchronized锁是一种悲观锁,通过加锁实现线程间同步。
(二)理解重量级锁在多线程环境下,如果使用synchronized锁,那么大概率会升级到重量级锁。偏向锁和轻量级锁非刻意为之,很难存在,更大的意义是对比帮助理解重量级锁的性能。
重量级锁尽管会对性能产生很大影响,但是依旧是解决线程间同步的有效手段。
1、选用锁的建议当被锁修饰的方法或者代码块执行时间较长时,选用基于线程阻塞-唤醒切换上下文的方式进行线程同步效率相对较高。
当被锁修饰的方法或者代码块执行时间较短时,应选用其它替代锁,比如自旋锁等。
在实际多线程场景开发中,synchronized锁大概率会升级到重量级锁,因其单向升级的特点,重量级状态的synchronized锁可能会对实际业务的并发产生不利影响,手动选用其它锁可能会更合适。
synchronized锁仅可用于解决同一进程内不同线程间同步,对于分布式项目跨进城线程同步依赖于分布式锁,synchronized锁更多的意义是理解锁的过程。
喜欢本文就一下,激励我持续创作。这个Github同样精彩,收到您的star我会很激动。本文归档在专题博客,视频讲解在B站。

