synchronized锁的对象
Java中每个对象都可以作为锁。具体表现为以下三种形式:
- 对于普通同步方法,锁是当前实例对象this
- 对于静态同步方法,锁是当前类字节码,Class对象
- 对于同步方法块,锁是synchronized括号里配置的对象
公平锁和非公平锁
非公平锁
private final ReentrantLock lock = new ReentrantLock();
// private final ReentrantLock lock = new ReentrantLock(false);
非公平锁,可能导致其他线程饿死。(一个人把活全干了,不问有没有人,直接抢)
效率高
公平锁
private final ReentrantLock lock = new ReentrantLock(true);
阳光普照,问一下有人没,有人就排队
效率相对低
可重入锁/递归锁
可重入锁特点演示:打开外层锁后,还可以继续打开内层锁
public static void main(String[] args) {
Object o = new Object();
new Thread(()->{
synchronized (o) {
System.out.println(Thread.currentThread().getName() + "外层");
synchronized (o) {
System.out.println(Thread.currentThread().getName() + "内层");
}
}
},"AA").start();
}
可重入锁可以实现重复递归调用
public class SyncLockDemo {
public synchronized void add(){
add();
}
public static void main(String[] args) {
new SyncLockDemo().add();
}
}
死锁
什么是死锁:
两个或两个以上的进程, 因为争夺资源而造成互相等待的现象,如果没有外力干涉,他们无法再执行下去
产生死锁的原因
- 系统资源不足
- 进程运行推进顺序不合适
- 资源分配不当
死锁例子
public class DeadLock {
//创建两个对象
static Object a = new Object();
static Object b = new Object();
public static void main(String[] args) {
new Thread(()->{
synchronized (a) {
System.out.println(Thread.currentThread().getName() + "持有锁a, 试图获取锁b");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (b) {
System.out.println(Thread.currentThread().getName() + "获取到锁b");
}
}
},"AA").start();
new Thread(()->{
synchronized (b) {
System.out.println(Thread.currentThread().getName() + "持有锁b, 试图获取锁a");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (a) {
System.out.println(Thread.currentThread().getName() + "获取到锁a");
}
}
},"BB").start();
}
}
验证是否是死锁
- jps -l 得到正在运行的程序进程号
- jstack 进程号 可以验证是否是死锁发生