Java中的同步机制概述
在Java多线程编程中,同步机制是一种用于协调多个线程对共享资源访问的机制。当多个线程同时访问共享资源时,可能会出现数据不一致、程序运行结果不符合预期等问题,同步机制的主要目的就是避免这些线程安全问题,确保在同一时刻只有一个线程可以访问共享资源,从而保证数据的一致性和完整性。
实现同步的方式
1. synchronized
关键字
- 同步方法:当一个方法被
synchronized
修饰时,同一时刻只有一个线程可以调用该方法。如果是实例方法,锁的是当前对象;如果是静态方法,锁的是当前类的Class
对象。
public class SynchronizedMethodExample {
private int count = 0;
public synchronized void increment() {
count++;
}
}
- 同步代码块:可以指定要锁定的对象,更加灵活。只有获取到指定对象的锁的线程才能执行同步代码块中的代码。
public class SynchronizedBlockExample {
private int count = 0;
private final Object lock = new Object();
public void increment() {
synchronized (lock) {
count++;
}
}
}
2. Lock
接口及其实现类
Lock
是 Java 并发包(java.util.concurrent.locks
)中定义的一个接口,常用的实现类有 ReentrantLock
。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
private int count = 0;
private final Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
}
3. ReadWriteLock
接口及其实现类
ReadWriteLock
提供了读锁和写锁,允许多个线程同时进行读操作,但写操作是互斥的。常用的实现类是 ReentrantReadWriteLock
。
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockExample {
private int data = 0;
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
public void writeData(int newData) {
rwLock.writeLock().lock();
try {
data = newData;
} finally {
rwLock.writeLock().unlock();
}
}
public int readData() {
rwLock.readLock().lock();
try {
return data;
} finally {
rwLock.readLock().unlock();
}
}
}
区别
1. 语法和使用方式
synchronized
关键字:是 Java 语言内置的同步机制,使用起来比较简单,不需要手动释放锁,当同步方法或同步代码块执行完毕后,锁会自动释放。Lock
接口:需要手动加锁和解锁,通过调用lock()
方法加锁,unlock()
方法解锁,通常需要在finally
块中调用unlock()
以确保锁一定会被释放。
2. 锁的获取和释放的灵活性
synchronized
关键字:锁的获取和释放是隐式的,无法中断一个正在等待获取锁的线程,也无法尝试获取锁(如果锁不可用,线程只能一直等待)。Lock
接口:提供了更灵活的锁获取方式,例如可以使用tryLock()
方法尝试获取锁,如果锁不可用,线程可以继续执行其他操作;还可以使用lockInterruptibly()
方法允许线程在等待锁的过程中被中断。
3. 锁的类型
synchronized
关键字:只有一种锁类型,即排他锁,同一时刻只允许一个线程访问共享资源。ReadWriteLock
接口:提供了读锁和写锁,读锁允许多个线程同时进行读操作,提高了并发性能,适用于读多写少的场景。
4. 性能
synchronized
关键字:在 JDK 1.6 之前,性能相对较低,但在 JDK 1.6 及以后,对synchronized
进行了大量的优化,性能有了很大的提升,在大多数情况下与Lock
接口的性能相当。Lock
接口:在高并发场景下,尤其是需要更灵活的锁控制时,Lock
接口的性能可能会更好。