本文正在参与「金石方案」
1、Synchronized与Lock对比
- 完成办法:Synchronized是Java言语内置的关键字,而Lock是一个Java接口。
- 锁的获取和开释:Synchronized是隐式获取和开释锁,由Java虚拟机主动完结;而Lock需求显式地调用lock()办法获取锁,并且必须在finally块中调用unlock()办法来开释锁。
- 可中止性:在获取锁的过程中,假如线程被中止,synchronized会抛出InterruptedException反常并且主动开释锁,而Lock则需求手动捕获InterruptedException反常并处理,同时也支撑非堵塞、可轮询以及定时获取锁的办法。
- 公正性:Synchronized不确保线程获取锁的公正性,而Lock能够经过结构函数指定公正或非公正锁。
- 锁状况:Synchronized无法判别锁的状况,而Lock能够经过tryLock()、isLocked()来判别锁的状况(线程是否或许取到锁、锁是否被占用等)。
- 粒度:Synchronized锁的粒度较粗,只能锁住整个办法或代码块,而Lock能够细粒度地操控锁的规模,比方锁某个目标的部分属性。
- 场景:假如在简略的并发场景下,推荐运用Synchronized;而在需求更高档的锁操控时,能够考虑运用Lock。
一般状况建议运用Synchronized,在JDK1.5之前Lock优于Synchronized,但在JDK1.5之后对Synchronized进行了优化,后面在性能方面基本与Lock相同且运用简略(有作者说”Synchronized是亲生的,JDK还是会一向优化他不会让Lock优于它”)。
2、Synchronized与Lock原理
2.1 Synchronized原理
Synchronized是Java言语中最常用的同步机制之一,它能够确保多个线程拜访共享资源时的互斥性和可见性。Synchronized关键字的原理如下:
- Synchronized运用了内置锁(也称为监视器锁)来完成同步。每个Java目标都有一个内置锁,当该目标作为锁被获取时,其他企图获取该锁的线程会被堵塞,直到该锁被开释。
- Synchronized的锁是与目标相关联的。当一个线程进入Synchronized代码块时,它必须先获取该目标的锁才能履行代码,否则就会被堵塞。当该线程退出Synchronized代码块时,它会主动开释该目标的锁。
- Synchronized具有可重入性。假如当时线程现已获得了某个目标的锁,那么它能够持续拜访该目标的其他Synchronized代码块,而不会被自己持有的锁所堵塞。
- Synchronized还具有volatile变量的读写语义。在运用Synchronized关键字时,内存屏障会确保本地线程中修正过的变量值被改写回主内存,然后确保了多个线程之间对变量修正的可见性。
Synchronized经过运用内置锁、与目标关联的锁、可重入性以及内存屏障等机制来完成线程的同步和锁的办理,以确保对共享资源的拜访具有互斥性和可见性。
2.2 Lock原理
Lock是Java言语中的一种高档同步机制,它供给了比Synchronized更加灵敏和可扩展的同步特性。Lock机制的原理如下:
- Lock运用了目标的锁来完成同步。每个Lock目标都有一个锁,当该锁被获取时,其他企图获取该锁的线程会被堵塞,直到该锁被开释。
- Lock的锁是与目标无关的。相比于Synchronized关键字,Lock供给了更加灵敏的办法来操控锁的获取和开释。例如,它支撑可中止的获取锁操作、超时获取锁操作等等。因而,在需求手动操控锁的获取和开释时,Lock是一个很好的选择。
- Lock还具有可重入性。假如当时线程现已获得了某个Lock目标的锁,那么它能够持续拜访该目标的其他Lock代码块,而不会被自己持有的锁所堵塞。
- Lock运用了条件变量来完成线程的等候和告诉。Condition接口供给了await()、signal()和signalAll()等办法,用于线程之间的等候和告诉,然后防止了Object类中wait()和notify()办法或许出现的信号丢失问题。
Lock经过运用目标的锁、与目标无关的锁、可重入性以及条件变量等机制来完成线程的同步和锁的办理,以确保对共享资源的拜访具有互斥性和可见性。与Synchronized关键字相比,Lock供给了更加灵敏和可扩展的同步特性,但也需求更多的代码来操控锁的获取和开释。
3、Synchronized与Lock运用
下面分别给出Synchronized和Lock的运用示例。
Synchronized
public class Counter {
private int count;
public synchronized void increment() {
count++;
}
}
上述代码界说了一个计数器类Counter,办法都运用了synchronized关键字来完成线程同步。
Lock
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Counter {
private int count;
private Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
}
上述代码也是界说了一个计数器类Counter,可是运用的是Lock接口来完成线程同步。在这种状况下,需求先创建一个ReentrantLock目标,然后在需求同步的代码块中调用lock()办法获取锁,在finally块中调用unlock()办法开释锁。
总的来说,Synchronized更加简略易用,合适用于一些简略的并发场景;而Lock供给了更多的灵敏性和可扩展性,合适用于一些复杂的并发场景。
4、相关问题
1)Synchronized和Lock有什么区别?
- 完成办法:Synchronized是Java内置的关键字,而Lock是一个接口。
- 锁的获取和开释:Synchronized的获取和开释锁由JVM主动完结,而Lock需求手动调用lock()办法获取锁并在finally块中调用unlock()办法开释锁。
- 可中止性:假如线程在获取锁的过程中被中止,Synchronized会抛出InterruptedException反常并主动开释锁,而Lock需求手动处理这种状况。
- 公正性:Synchronized不确保公正性,而Lock能够经过结构函数指定公正或非公正锁。
- 粒度:Synchronized锁的粒度比较粗,只能锁住整个办法或代码块,而Lock能够细粒度地操控锁的规模。
2)Synchronized的完成原理是什么?
Synchronized是根据Java目标头的监视器(Monitor)完成的。每个Java目标都有一个监视器,同步块的进入和退出需求获取和开释目标的监视器。当线程尝试进入一个被锁住的同步块时,它会先尝试获取目标的监视器锁,假如锁现已被占用,线程就会进入堵塞状况,直到锁被开释。
3)Lock的完成原理是什么?
Lock的完成是根据Java的AbstractQueuedSynchronizer(AQS)框架的。Lock接口界说了多个获取和开释锁的办法,其中比较重要的是lock()和unlock()办法。当一个线程调用lock()办法获取锁时,假如锁未被占用,则该线程会占用锁并持续履行;否则,该线程会进入堵塞状况,直到锁被开释。当一个线程调用unlock()办法开释锁时,会告诉等候行列中的其他线程持续尝试获取锁。
4)什么是可重入锁?
可重入锁指的是同一个线程在持有锁的状况下,能够再次获取该锁,而不会导致死锁。Synchronized和ReentrantLock都是可重入锁。可重入锁经过记载持有锁的线程和重入次数,来防止死锁的产生。
5)ReentrantLock为什么比Synchronized更灵敏?
ReentrantLock比Synchronized更灵敏首要因为它供给了以下功能:
- 能够指定公正锁或非公正锁。
- 支撑获取锁的超时时刻。
- 支撑可中止的获取锁操作。
- 能够经过tryLock()办法尝试获取锁,假如锁现已被占用,则返回false。
- 支撑多个Condition目标,能够让线程在不同的条件下等候和唤醒。
6)什么是锁自旋?
锁自旋是一种优化锁竞争的技能,它用于削减线程在获取锁时的等候时刻。当一个线程请求获取某个目标的锁时,假如此时锁现已被其他线程占用,那么该线程会进入堵塞状况等候锁的开释。而运用锁自旋技能,线程在发现锁被其他线程占用时,并不会当即进入堵塞状况,而是履行一段循环代码(称为自旋),等候锁的持有者开释锁。
———————————————————–
假如文章对你有协助,趁便加个关注,点个赞!!!
本文正在参与「金石方案」