一、动态锁(对象锁):线程间的互斥
动态锁,也称为对象锁,是 synchronized 关键字修饰非静态方法或同步代码块时产生的锁。
- 锁定对象:动态锁锁住的是当前对象实例(
this) 。 - 互斥范围:同一时刻,只有一个线程可以访问同一个对象实例的同步方法或同步代码块。但不同线程可以同时访问不同对象实例的同步方法。
public class DynamicLockDemo {
// 动态锁方法,锁住this对象
public synchronized void instanceMethod() {
System.out.println(Thread.currentThread().getName() + "进入实例方法");
// ...
}
public void anotherMethod() {
// 动态锁代码块,锁住this对象
synchronized (this) {
System.out.println(Thread.currentThread().getName() + "进入同步代码块");
// ...
}
}
}
二、静态锁(类锁):全局的互斥
静态锁,也称为类锁,是 synchronized 关键字修饰静态方法或同步代码块(以 ClassName.class 为参数)时产生的锁。
- 锁定对象:静态锁锁住的是该类的
Class对象。 - 互斥范围:同一时刻,只有一个线程可以访问该类的静态同步方法或同步代码块。因为每个类在 JVM 中只有一个
Class对象,所以静态锁是全局唯一的。
public class StaticLockDemo {
// 静态锁方法,锁住StaticLockDemo.class
public static synchronized void staticMethod() {
System.out.println(Thread.currentThread().getName() + "进入静态方法");
// ...
}
public void instanceMethod() {
// 静态锁代码块,锁住Class对象
synchronized (StaticLockDemo.class) {
System.out.println(Thread.currentThread().getName() + "进入同步代码块");
// ...
}
}
}
三、死锁:多线程并发的致命陷阱
死锁是多线程并发中的一种僵局。当两个或多个线程各自持有一个锁,并试图获取对方持有的锁时,就会发生死锁。
-
四大必要条件:
- 互斥(Mutual Exclusion) :一个锁一次只能被一个线程持有。
- 请求和保持(Hold and Wait) :线程已经持有一个锁,同时又在请求另一个锁。
- 不可抢占(No Preemption) :锁只能由持有它的线程释放,不能被其他线程强制剥夺。
- 循环等待(Circular Wait) :多个线程形成一个环形等待链。
-
避免死锁的策略:
- 固定锁顺序:所有线程都按照相同的顺序获取锁。
- 超时获取锁:使用
ReentrantLock的tryLock()方法,在指定时间内无法获取锁时,自动放弃。 - 减少锁粒度:只在需要同步的代码块上加锁,以减小锁的范围。