您好,登录后才能下订单哦!
# 怎么用Java实现synchronized锁同步机制
## 一、并发编程中的同步问题
### 1.1 为什么需要同步机制
在多线程编程中,当多个线程同时访问共享资源时,如果没有适当的同步机制,可能会导致数据不一致、竞态条件等问题。例如:
```java
public class Counter {
private int count = 0;
public void increment() {
count++; // 这不是原子操作
}
public int getCount() {
return count;
}
}
在这个简单的计数器例子中,count++
操作实际上包含三个步骤:读取当前值、增加1、写回新值。如果两个线程同时执行这个操作,可能会导致计数结果不正确。
public synchronized void method() {
// 同步代码块
}
这种形式锁的是当前实例对象(this),同一个实例的多个同步方法会互斥。
public static synchronized void staticMethod() {
// 同步代码块
}
这种形式锁的是当前类的Class对象,所有该类的实例调用这个静态方法都会互斥。
public void method() {
synchronized(obj) { // obj是锁对象
// 同步代码块
}
}
这种形式可以灵活指定锁对象,可以是任意对象实例。
每个Java对象都有一个内置锁(也称为监视器锁)。当线程进入synchronized方法或代码块时,会自动获取这个锁,退出时自动释放。
synchronized在JVM中的实现是基于进入和退出Monitor对象来实现的:
Java对象在内存中的布局分为三部分:
其中对象头包含Mark Word和类型指针。Mark Word是实现synchronized的关键:
|-------------------------------------------------------|--------------------|
| Mark Word (32 bits) | State |
|-------------------------------------------------------|--------------------|
| hashcode:25 | age:4 | biased_lock:1 | lock:2 (01) | Normal |
|-------------------------------------------------------|--------------------|
| thread:23 | epoch:2 | age:4 | biased_lock:1 | lock:2 (01) | Biased |
|-------------------------------------------------------|--------------------|
| ptr_to_lock_record:30 | lock:2 (00) | Lightweight Locked |
|-------------------------------------------------------|--------------------|
| ptr_to_heavyweight_monitor:30 | lock:2 (10) | Heavyweight Locked |
|-------------------------------------------------------|--------------------|
| | lock:2 (11) | Marked |
|-------------------------------------------------------|--------------------|
JDK 1.6之后,synchronized实现了锁升级机制:
这种优化减少了锁操作的开销。
synchronized是可重入锁,同一个线程可以多次获取同一个锁:
public class ReentrantDemo {
public synchronized void method1() {
method2(); // 可以调用另一个同步方法
}
public synchronized void method2() {
// ...
}
}
synchronized配合wait()/notify()/notifyAll()实现线程间通信:
public class WaitNotifyDemo {
private final Object lock = new Object();
private boolean condition = false;
public void waitForCondition() throws InterruptedException {
synchronized(lock) {
while(!condition) {
lock.wait(); // 释放锁并等待
}
// 条件满足后的处理
}
}
public void setCondition() {
synchronized(lock) {
condition = true;
lock.notifyAll(); // 唤醒所有等待线程
}
}
}
synchronized使用不当可能导致死锁:
public class DeadlockDemo {
private final Object lock1 = new Object();
private final Object lock2 = new Object();
public void method1() {
synchronized(lock1) {
synchronized(lock2) {
// ...
}
}
}
public void method2() {
synchronized(lock2) {
synchronized(lock1) {
// ...
}
}
}
}
将大同步块拆分为小同步块:
// 不推荐
public synchronized void processBigData() {
// 大量处理逻辑
}
// 推荐
public void processBigData() {
// 非同步处理
synchronized(this) {
// 只同步必要部分
}
// 非同步处理
}
public class FineGrainedLock {
private final Object readLock = new Object();
private final Object writeLock = new Object();
public void read() {
synchronized(readLock) {
// 读操作
}
}
public void write() {
synchronized(writeLock) {
// 写操作
}
}
}
public void process() {
// 耗时的非同步操作
List<Data> dataList = fetchDataFromDB();
synchronized(this) {
// 快速更新共享状态
updateSharedState(dataList);
}
}
特性 | synchronized | ReentrantLock |
---|---|---|
实现方式 | JVM内置实现 | JDK代码实现 |
锁获取方式 | 自动获取和释放 | 需要手动lock()和unlock() |
可中断 | 不支持 | 支持lockInterruptibly() |
公平锁 | 非公平 | 可选择公平或非公平 |
条件变量 | 只能有一个条件 | 可创建多个Condition |
性能 | JDK6后优化良好 | 高竞争下性能更好 |
// 不推荐 - 锁字符串常量可能有问题
synchronized("LOCK") {
// ...
}
// 推荐 - 使用私有final对象
private final Object lock = new Object();
public void method() {
synchronized(lock) {
// ...
}
}
// 不推荐
public synchronized void process() {
// ...
}
// 推荐
private final Object lock = new Object();
public void process() {
synchronized(lock) {
// ...
}
}
public class Singleton {
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
注意:必须使用volatile防止指令重排序。
JVM会进行优化:
synchronized是非公平锁,可能导致线程饥饿。如果需要公平锁,可以使用ReentrantLock。
public class SafeCounter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
public class ProducerConsumer {
private final Queue<Integer> queue = new LinkedList<>();
private final int CAPACITY = 10;
private final Object lock = new Object();
public void produce(int value) throws InterruptedException {
synchronized(lock) {
while(queue.size() == CAPACITY) {
lock.wait();
}
queue.add(value);
lock.notifyAll();
}
}
public int consume() throws InterruptedException {
synchronized(lock) {
while(queue.isEmpty()) {
lock.wait();
}
int value = queue.poll();
lock.notifyAll();
return value;
}
}
}
synchronized是Java中最基本的同步机制,虽然看起来简单,但深入理解其实现原理和最佳实践对于编写高效、安全的并发程序至关重要。随着JDK版本的更新,synchronized的性能已经得到了显著提升,在大多数场景下都是不错的选择。
通过本文的系统学习,相信读者已经掌握了synchronized的核心概念和使用技巧。在实际开发中,应根据具体场景选择合适的同步策略,平衡性能与正确性的需求。 “`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。