synchronized 和 ReentrantLock 都是 Java 中的同步机制,用于确保在多线程环境下,同一时刻只有一个线程能够访问特定的代码块、方法或对象。它们的区别在于实现方式和性能上。
synchronized、ReentrantLock
synchronized
synchronized 是关键字,可以用于修饰方法或代码块。当使用 synchronized 修饰方法或代码块时,整个修饰的代码块或方法被锁住,只有当锁被释放时,才能继续执行。(加锁解锁以及锁升级过程由JVM自动控制)
示例
public class BiasLockExample {
private static final Object LOCK = new Object();
private static int count = 0;
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
synchronized (LOCK) {
count++;
}
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
synchronized (LOCK) {
count++;
}
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Count: " + count);
}
}
ReentrantLock
ReentrantLock 是 API,通过实现 java.util.concurrent.locks.Lock 接口来提供锁功能。所以就需要手动进行加锁解锁处理,ReentrantLock 提供了更多的高级功能,如可重入、公平性、可设置超时等。
可重入
意味着同一个线程可以多次获得同一个锁。synchronized也有这个特点。
公平性
ReentrantLock分为公平锁和非公平锁(默认非公平锁),具体用法是new ReentrantLock(true/false),当false的时候是非公平锁,true的时候是公平锁,非公平锁和公平锁的区别可以简单理解为:
在公平锁中,先申请锁的线程一定会先获得锁,而不会被后申请锁的线程抢到。而在非公平锁中就不一定了,谁抢到算谁的,不管申请锁的顺序。
示例
import java.util.concurrent.locks.ReentrantLock;
/**
* ReentrantLock(可重入锁)
*/
public class ReentrantLockTest {
//创建锁对象(入参为是否开启公平锁)
ReentrantLock lock = new ReentrantLock(false);
public void method(){
String thread_name = Thread.currentThread().getName();
System.out.println(thread_name +"当前是否上锁:"+lock.isLocked());
//加锁
lock.lock();
try {
Thread.sleep(500);
System.out.println(thread_name+"锁用完啦");
}catch (Exception e){
e.printStackTrace();
}finally {
//释放锁
lock.unlock();
}
}
public static void main(String[] args) {
ReentrantLockTest t = new ReentrantLockTest();
for (int i = 0; i < 5; i++) {
new Thread(() -> {
t.method();
},"ReentrantLockTest-"+i).start();
}
for (int i = 5; i < 10; i++) {
new Thread(() -> {
t.method();
},"ReentrantLockTest-"+i).start();
}
}
}