synchronized
“Synchronized” 是一个关键字,用于实现线程之间的同步。它可以应用于方法或代码块,确保在同一时间只有一个线程可以访问被标记的代码。
当一个线程获得了一个对象的同步锁后,其他线程将被阻塞,直到获得同步锁的线程释放锁。这可以防止多个线程同时修改共享数据,避免数据不一致或并发访问的问题。
synchronized的用法
1.修饰实例方法:
使用当前对象this充当锁,完成对当前方法的锁定,只有获取this锁的线程才能访问当前方法,并且在并发过程中,同一时刻,可以有N个线程请求执行方法,但只有一个线程可以持有this锁,才能执行;不同线程,持有的对象,必须相同;
public synchronized void dosth() {
// 获取this锁,才能执行该方法
}
public void dosth2() {
synchronized (this) {
// 获取this锁,才能执行该方法
}
}
2.修饰静态方法:
使用当前对象的Class对象充当锁,完成对当前方法的锁定,只有获取Class锁的线程才能访问当前方法;不同线程,持有的对象,可以不同,但必须相同class类型;
public synchronized static void dosth() {
// 获取当前对象的Class对象锁,才能执行该代码块
}
public void dosth2() {
synchronized (this.getClass) {
// 获取当前对象的Class对象锁,才能执行该代码块
}
}
obj是一个要同步的对象,只有获得obj的同步锁的线程可以执行被同步的代码块。
ReentrantLock
从Java 5开始,引入了一个高级处理并发java.util.concurrent包,它提供了大量更高级的并发功能,能大大简化多线程程序的编写。
synchronized关键字虽然已经实现可重入锁,但由于获取时必须一直等待,没有额外的尝试机制。所以,在java.util.concurrent.locks包提供的ReentrantLock用于替代synchronized。顾名思义,ReentrantLock也是可重入锁,它和synchronized一样,一个线程可以多次获取同一个锁。
与synchronized关键字不同,ReentrantLock是一个类而不是关键字,它实现了Lock接口。使用ReentrantLock可以实现与synchronized类似的线程同步效果,但具有更多的扩展和控制选项。
public class Example {
private ReentrantLocklock = new ReentrantLock();
public void dosth() {
lock.lock();//获取锁
try {
...
} finally {
lock.unlock();//释放锁
}
}
}
和synchronized不同的是,synchronized是Java语言层面提供的语法,所以我们不需要考虑异常,而ReentrantLock是JavaSE核心类库的并发包给我们提供的的可重入锁,所以,在编程过程中,我们就必须先创建锁,结束后在finally中正确释放锁。
ReentrantLock与synchronized的区别
- 可扩展性:ReentrantLock相对于synchronized提供了更多的灵活性和可扩展性。它提供了诸如公平性、条件变量、中断响应等功能,使得线程同步更加灵活。相比之下,synchronized关键字是Java语言内置的关键字,提供了基本的线程同步功能,但不具备同样的扩展性。
- 获取锁的方式:ReentrantLock提供了多种获取锁的方式。它可以使用lock()方法获取锁,并使用unlock()方法释放锁。另外,ReentrantLock还支持可中断的获取锁方式,即使用lockInterruptibly()方法,在等待锁的过程中可以响应中断。相比之下,使用synchronized关键字获取锁是隐式的,线程进入同步代码块时会自动获取锁,退出同步代码块时会自动释放锁,无法中断获取锁的过程。
- 锁的公平性:ReentrantLock可以选择公平性获取锁的方式,即按照线程请求锁的顺序来获取锁。而synchronized关键字在获取锁时没有公平性的概念,可能会导致某些线程长时间等待锁的情况,出现线程饥饿问题。
- 异常处理:ReentrantLock允许显式地使用try-finally语句来确保在获取锁后一定会释放锁,从而避免锁泄漏。而synchronized关键字在获取锁和释放锁的过程中,由Java虚拟机自动管理,不需要手动处理。
- 锁的实现机制:ReentrantLock采用的是AQS(AbstractQueuedSynchronizer),用于实现基于队列的线程同步器;而synchronized采用的监视器(Monitor)是一种线程同步机制,用于在多线程环境下保护共享资源的一致性和正确性。