5 多线程锁

5.1 锁的八个问题演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Phone {
public static synchronized void sendSMS() throws Exception {
//停留 4 秒
TimeUnit.SECONDS.sleep(4);
System.out.println("------sendSMS");
}

public synchronized void sendEmail() throws Exception {
System.out.println("------sendEmail");
}

public void getHello() {
System.out.println("------getHello");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
1 标准访问,先打印短信还是邮件
------sendSMS
------sendEmail
2 停 4 秒在短信方法内,先打印短信还是邮件
------sendSMS
------sendEmail
3 新增普通的 hello 方法,是先打短信还是 hello
------getHello
------sendSMS
4 现在有两部手机,先打印短信还是邮件
------sendEmail
------sendSMS
5 两个静态同步方法,1 部手机,先打印短信还是邮件
------sendSMS
------sendEmail
6 两个静态同步方法,2 部手机,先打印短信还是邮件
------sendSMS
------sendEmail
7 1 个静态同步方法,1 个普通同步方法,1 部手机,先打印短信还是邮件
------sendEmail
------sendSMS
8 1 个静态同步方法,1 个普通同步方法,2 部手机,先打印短信还是邮件
------sendEmail
------sendSMS

结论

一个对象里面如果有多个synchronized方法,某一时刻内,只要一个线程去调用其中的一个synchronized方法了,其它的线程智能等待,换句话说,某一个时刻内,只能有唯一一个线程去访问这些synchronized方法

锁的是当前对象this,被锁定后,其它的线程都不能进入到当前对象的其他synchronized方法

加个普通方法后发现和同步锁无关

换成两个对象后,不是同一把锁了,情况立刻变化。

synchronized实现同步的基础:Java中的每一个对象都可以作为锁。

具体表现为以下3种形式。

对于普通同步方法,锁是当前实例对象。

对于静态同步方法,锁是当前类的Class对象。

对于同步方法块,锁是synchronized括号里配置的对象

当一个线程试图访问同步代码块时,它首先必须得到锁,退出或抛出异常时必须释放锁。也就是说如果一个实例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁,可是别的实例对象的非静态同步方法因为跟该实例对象的非静态同步方法用的是不同的锁,所以毋须等待该实例对象已获取锁的非静态同步方法释放锁就可以获取他们自己的锁。所有的静态同步方法用的也是同一把锁——类对象本身,这两把锁是两个不同的对象,所以静态同步方法与非静态同步方法之间是不会有竞态条件的。但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁,而不管是同一个实例对象的静态同步方法之间,还是不同的实例对象的静态同步方法之间,只要它们同一个类的实例对象!

5.2 公平锁和非公平锁

非公平锁:线程饿死,效率高

公平锁:多个线程按照申请锁的顺序去获得锁,线程会直接进入队列去排队,永远都是队列的第一位才能得到锁(线程争夺cpu,效率低)

5.3 可重入锁和不可重入锁

可重入锁:synchronized(隐式,jvm层面上锁和解锁)和Lock(显示)都是可重入锁。

可重入锁也叫递归锁,指的是以线程为单位,当一个线程获取对象锁之后,这个线程可以再次获取本对象上的锁,而其他的线程是不可以的

不可重入锁:所谓不可重入锁,即若当前线程执行某个方法已经获取了该锁,那么在方法中尝试再次获取锁时,就会获取不到被阻塞。(同一把锁)

5.4 死锁

1.什么是死锁?

两个或者两个以上进程在执行过程中,因为争夺资源二造成一种互相等待的现象,如果没有外力干涉,它们就无法再执行下去。

2.产生死锁的原因?(线程互斥、请求保持、循环等待)

  • 第一 系统资源不足
  • 第二 进程运行推进顺序不合适
  • 第三 资源分配不当

3.验证是否死锁

(1)jps -l 类似Linux ps -ef

(2)jstack jvm自带堆栈跟踪工具

5.5 乐观锁和悲观锁

5.6 自旋锁

5.7 独占锁与共享锁

5.8 读写锁

5.9 同步锁(互斥锁)