java中synchronized的轻量级锁和重量级锁的用法
时间: 2023-05-26 17:01:43 浏览: 138
在 Java 中,synchronized 是用来实现线程同步的关键字,它包含了两种锁的实现方式:轻量级锁和重量级锁。
轻量级锁:轻量级锁是指在没有竞争的情况下,使用 CAS 操作来进行加锁和解锁操作。当线程占有锁时,使用 CAS 将锁对象的对象头的 Mark Word 修改为指向锁拥有的线程的栈帧的锁记录。轻量级锁的优点在于,在竞争不激烈的情况下,加锁和解锁的开销较小,性能较高。
重量级锁:重量级锁是指在竞争激烈的情况下,使用操作系统的互斥量来进行加锁和解锁操作。当锁对象被多个线程争抢时,轻量级锁会逐渐升级为重量级锁,这时需要通过操作系统的互斥量来进行加锁和解锁操作,开销较大。
在 Java 中,synchronized 默认使用的是重量级锁,但是当 synchronized 应用在方法上时,JVM 会自动地选择合适的锁类型,包括轻量级锁和偏向锁等。因此,在使用 synchronized 关键字时,需要根据实际情况进行权衡和选择,以达到更好的性能和效果。
相关问题
解释一下 Synchronized 中 偏向锁 轻量级锁 重量级锁的 含义,并且用例子解释一下
Synchronized 是 Java 中用于实现线程同步的关键字,它可以保证在同一时刻只有一个线程可以访问被 Synchronized 修饰的代码块或方法。在实现线程同步时,Synchronized 使用了不同的锁,包括偏向锁、轻量级锁和重量级锁。
偏向锁是一种针对单线程场景的优化锁,它会在第一次获取锁时,将当前线程 ID 记录在锁的对象头中,之后该线程再次获取锁时,无需竞争锁资源,直接获取锁即可。举个例子:
```java
public class BiasLockExample {
private static Object lock = new Object();
public static void main(String[] args) {
long start = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
synchronized (lock) {
// do something
}
}
System.out.println("Time cost: " + (System.currentTimeMillis() - start) + "ms");
}
}
```
在以上代码中,由于所有的锁都是在同一个线程中获取的,因此会使用偏向锁进行优化,从而提高了程序的执行效率。
轻量级锁是一种适用于竞争不激烈的场景的锁,它会在第一次获取锁时,将对象头中的信息复制到线程栈中,然后通过 CAS 操作来更新对象头中的信息,如果更新成功,则表示该线程获取了锁,如果失败,则需要升级为重量级锁。举个例子:
```java
public class LightweightLockExample {
private static Object lock = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " got the lock");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(() -> {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " got the lock");
}
}).start();
}
}
```
在以上代码中,由于第一个线程获取锁后会休眠 5 秒钟,因此第二个线程需要等待第一个线程释放锁之后才能获取锁,而这时就会使用轻量级锁进行优化。
重量级锁是一种适用于竞争激烈的场景的锁,它会导致线程阻塞,从而消耗大量的系统资源。举个例子:
```java
public class HeavyweightLockExample {
private static Object lock = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " got the lock");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(() -> {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " got the lock");
}
}).start();
}
}
```
在以上代码中,由于两个线程同时竞争同一个锁,因此会使用重量级锁进行优化,从而导致第二个线程需要等待第一个线程释放锁之后才能获取锁,这样会导致线程阻塞,从而影响程序的执行效率。
synchronized 重量级锁
synchronized 关键字在 Java 中用于实现线程同步,其中的重量级锁是指 synchronized 在底层实现上使用的一种锁机制。
在 Java 中,synchronized 可以用于修饰实例方法、静态方法和代码块。当 synchronized 关键字修饰一个方法或代码块时,它会获取对象的锁,并且在执行完 synchronized 代码块后会释放锁。
重量级锁是指 synchronized 在底层使用的一种互斥量实现,也称为悲观锁。它的特点是在多线程竞争情况下,会导致其他线程阻塞等待锁的释放,从而影响程序的性能。
在 Java 6 及之前的版本中,synchronized 关键字使用的是重量级锁(也称为监视器锁或内部锁)的实现方式。这种实现方式是基于操作系统的互斥量来实现的,需要进行用户态和内核态的切换,开销较大。
然而,在 Java 6 Update 23 及之后的版本中,JVM 引入了偏向锁、轻量级锁和重量级锁三种状态来提高 synchronized 的性能。在没有竞争的情况下,synchronized 会使用偏向锁和轻量级锁,只有在竞争激烈时才会升级为重量级锁。
总结来说,重量级锁是 synchronized 在底层实现中使用的一种互斥量,它的特点是在多线程竞争情况下会导致其他线程阻塞等待锁的释放,性能相对较低。但在 Java 6 Update 23 及以后的版本中,JVM 引入了偏向锁和轻量级锁来提高 synchronized 的性能。
阅读全文