1.Java同步机制的演进历程
在多线程编程中,同步机制是保证数据一致性和线程安全的关键。Java在早期版本中引入了synchronized关键字,它提供了一种简单的锁机制来控制对共享资源的并发访问。随着Java语言的发展,synchronized的性能得到了显著提升,但在某些场景下仍然显得力不从心。因此,在JDK 1.5中引入了java.util.concurrent.locks.Lock接口,它提供了更灵活的锁操作,允许尝试非阻塞获取锁、可中断的锁等候以及公平锁等高级功能。
public class SynchronizedVsLock {
private int counter = 0;
public synchronized void incrementSync() {
counter++;
}
private final Lock lock = new ReentrantLock();
public void incrementLock() {
lock.lock();
try {
counter++;
} finally {
lock.unlock();
}
}
}
2.synchronized的实现和限制
synchronized是基于监视器锁(Monitor Lock)的同步原语,它保证了同一时刻只有一个线程可以访问被同步的代码块或方法。synchronized锁定的是对象和类,当作用于实例方法时,锁定的是调用该方法的对象实例;当作用于静态方法时,锁定的是方法所在的Class对象。
尽管synchronized使用起来相对简单直观,但它存在一些局限性:
- 不可中断:一旦线程进入了阻塞状态,就没有办法中断它,只能等待其他线程释放锁。
- 不可尝试:synchronized没有提供尝试获取锁的机制,线程只能直接获取锁或者阻塞。
- 不公平:synchronized不保证等待的线程获取锁的顺序,可能会产生“饥饿”现象。
public class SynchronizedExample {
public synchronized void syncMethod() {
// Critical section
}
public void syncBlock() {
synchronized (this) {
// Critical section
}
}
}
3. 高级同步:Lock接口简介
为了解决synchronized的一些局限性,Java 5引入了java.util.concurrent.locks.Lock接口,它提供了比synchronized更丰富的锁操作。它允许更灵活的结构,可以有选择地获取锁,在等待锁的时候可以响应中断,还可以尝试非阻塞地获取锁,或者在尝试获取锁时等待一段时间。
Lock接口提供了以下几个重要方法:
- lock():如果锁不可用,则当前线程将被阻塞。
- lockInterruptibly():如果当前线程未被中断,则获取锁。
- tryLock():仅在调用时锁空闲时才获取锁。
- tryLock(long time, TimeUnit unit):如果锁在给定等待时间内没有被另一个线程持有,且当前线程未被中断,则获取锁。
- unlock():释放锁。
public class LockExample {
private final Lock lock = new ReentrantLock();
public void performTask() {
lock.lock();
try {
// Critical section code
} finally {
lock.unlock();
}
}
public void taskWithTimeout() throws InterruptedException {
if (lock