您好,登录后才能下订单哦!
# 怎么用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进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。