Java并发编程深入理解之Synchronized的使用及底层原理详解
Synchronized简介
Synchronized是Java中最基本的互斥同步手段,它提供了一种独占的锁机制,同一时刻只能有一个线程访问被同步的代码块,其他线程必须等待当前线程释放锁后才能继续执行。
Synchronized的使用
Synchronized的使用非常简单,只需在方法或代码块前面加上synchronized关键字即可。
同步方法
public synchronized void method() {
// 一些需要同步的代码
}
使用synchronized关键字修饰方法时,锁对象为当前实例对象。
同步代码块
public void method() {
synchronized (this) {
// 一些需要同步的代码
}
}
使用synchronized关键字修饰代码块时,锁对象为括号中的对象,一般使用this代表当前实例对象。只有拥有锁的线程才能执行被同步的代码块,其他线程必须等待。
Synchronized的底层原理
Synchronized保证了同一时刻只有一个线程执行代码的原因是基于Java中的对象头和monitorenter/monitorexit指令实现的。
对象头
在Java中,每个对象都有一个对象头,对象头包含了两类信息:
- 存储对象的哈希值(HashCode)和锁标记位信息,锁标记位信息用来描述当前对象是否被加锁
- 类型指针,指向对象所属的类或元数据信息
monitorenter/monitorexit指令
monitorenter指令用来获取对象的锁,并将锁计数器+1;而monitorexit指令用来释放锁,并将锁计数器-1。当锁计数器等于0时,表示锁已经被释放。
当一个线程要访问被synchronized修饰的方法或代码块时,JVM首先会尝试获取锁。如果该锁已经被其他线程获得,则当前线程会被阻塞,直到该锁被释放为止。
示例说明
同步方法示例
public class SyncMethodDemo {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized void decrement() {
count--;
}
public int getCount() {
return count;
}
}
在SyncMethodDemo类中定义了三个方法:increment、decrement和getCount,increment和decrement方法都通过synchronized关键字修饰,因此它们都是同步方法。这意味着在同一时刻只能有一个线程访问这两个方法,其他线程必须等待。
同步代码块示例
public class SyncBlockDemo {
private int count = 0;
public void add() {
synchronized(this) {
count++;
}
}
public void subtract() {
synchronized(this) {
count--;
}
}
public int getCount() {
return count;
}
}
在SyncBlockDemo类中,我们定义了两个方法add和subtract,它们都包含了一个synchronized关键字修饰的同步代码块,锁对象是当前实例对象this。因此在同一时刻只能有一个线程访问add和subtract方法,其他线程必须等待。
以上示例说明了Synchronized的使用方法和底层原理,Synchronized虽然简单,但在保证并发安全方面是非常重要的。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java并发编程深入理解之Synchronized的使用及底层原理详解 下 - Python技术站