经典8锁问题--助你彻底搞懂锁的概念

经典8锁问题--助你彻底搞懂锁的概念

viEcho Lv5

下面将通过经典的8锁问题,认清锁原理

场景一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.util.concurrent.TimeUnit;

/**
* 标准情况下 是先sendEmail() 还是先callPhone()?
* 答案:sendEmail
* 解释:被 synchronized 修饰的方式,锁的对象是方法的调用者
* 所以说这里两个方法调用的对象是同一个,先调用的先执行!
*/
public class LockDemo1 {
public static void main(String[] args) throws InterruptedException {
Phone1 phone1 = new Phone1();
new Thread(()->{
phone1.sendEmail();
},"A").start();
TimeUnit.SECONDS.sleep(3);
new Thread(()->{
phone1.callPhone();
},"B").start();
}
}
class Phone1{
public synchronized void sendEmail(){
System.out.println("senEmail");
}
public synchronized void callPhone(){
System.out.println("callPhone");
}
}

场景二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import java.util.concurrent.TimeUnit;

/**
* sendEmail()休眠三秒后 是先执行sendEmail() 还是 callPhone()
* 答案: sendEmail
* 解释:被 synchronized 修饰的方式,锁的对象是方法的调用者
* 所以说这里两个方法调用的对象是同一个,先调用的先执行!
*/
public class LockDemo2 {
public static void main(String[] args) throws InterruptedException {
Phone2 phone2 = new Phone2();
new Thread(()->{
try {
phone2.sendEmail();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"A").start();
TimeUnit.SECONDS.sleep(2); // 休眠2秒
new Thread(()->{
phone2.callPhone();
},"B").start();
}
}
class Phone2{
public synchronized void sendEmail() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
System.out.println("sendEmail");
}
public synchronized void callPhone(){
System.out.println("callPhone");
}
}

场景三

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import java.util.concurrent.TimeUnit;

/**
* 被synchronized 修饰的方式和普通方法 先执行sendEmail() 还是 callPhone()
* 答案: callPhone
* 解释:新增加的这个方法没有 synchronized 修饰,不是同步方法,不受锁的影响!
*/
public class LockDemo3 {
public static void main(String[] args) throws InterruptedException {
Phone3 phone3 = new Phone3();
new Thread(()->{
try {
phone3.sendEmail();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"A").start();

TimeUnit.SECONDS.sleep(2);
new Thread(()->{
phone3.callPhone();
},"B").start();
}
}
class Phone3{
public synchronized void sendEmail() throws InterruptedException {
TimeUnit.SECONDS.sleep(4);
System.out.println("sendEmail");
}

// 没有synchronized 没有static 就是普通方式
public void callPhone(){
System.out.println("callPhone");
}
}

场景四

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import java.util.concurrent.TimeUnit;

/**
* 被synchronized 修饰的不同方法 先执行sendEmail() 还是callPhone()?
* 答案:callPhone
* 解释:被synchronized 修饰的不同方法 锁的对象是调用者
* 这里锁的是两个不同的调用者,所有互不影响
*/
public class LockDemo4 {
public static void main(String[] args) throws InterruptedException {
Phone4 phoneA = new Phone4();
Phone4 phoneB = new Phone4();

new Thread(()->{
try {
phoneA.sendEmail();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"A").start();

TimeUnit.SECONDS.sleep(1);
new Thread(()->{
phoneB.callPhone();
},"B").start();
}
}
class Phone4{
public synchronized void sendEmail() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
System.out.println("sendEmail");
}
public synchronized void callPhone(){
System.out.println("callPhone");
}
}

场景五

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import java.util.concurrent.TimeUnit;

/**
* 两个静态同步方法 都被synchronized 修饰 是先sendEmail() 还是callPhone()?
* 答案:sendEmial
* 解释:只要方法被 static 修饰,锁的对象就是 Class模板对象,这个则全局唯一!
* 所以说这里是同一个锁,并不是因为synchronized 这里程序会从上往下依次执行
*/
public class LockDemo5 {
public static void main(String[] args) throws InterruptedException {
Phone5 phone5 = new Phone5();
new Thread(()->{
try {
phone5.sendEmail();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"A").start();

TimeUnit.SECONDS.sleep(1);
new Thread(()->{
phone5.callPhone();
},"B").start();
}
}
class Phone5{
public static synchronized void sendEmail() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
System.out.println("sendEmail");
}

public static synchronized void callPhone(){
System.out.println("callPhone");
}
}

场景六

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import java.util.concurrent.TimeUnit;

/**
* 被synchronized 修饰的普通方法和静态方法 是先sendEmail() 还是 callPhone()?
* 答案:callPhone
* 解释:只要被static修饰锁的是class模板, 而synchronized 锁的是调用的对象
* 这里是两个锁互不影响,按时间先后执行
*/
public class LockDemo6 {
public static void main(String[] args) throws InterruptedException {
Phone6 phone6 = new Phone6();
new Thread(()->{
try {
phone6.sendEmail();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"A").start();

TimeUnit.SECONDS.sleep(1);
new Thread(()->{
phone6.callPhone();
},"B").start();
}
}
class Phone6{
public static synchronized void sendEmail() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
System.out.println("sendEmail");
}

public synchronized void callPhone(){
System.out.println("callPhone");
}
}

场景七

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import java.util.concurrent.TimeUnit;

/**
* 同被static+synchronized 修饰的两个方法,是先sendEmail()还是callPhone()?
* 答案:sendEmail
* 解释:只要方法被 static 修饰,锁的对象就是 Class模板对象,这个则全局唯一
* 所以说这里是同一个锁,并不是因为synchronized
*/
public class LockDemo7 {
public static void main(String[] args) throws InterruptedException {
Phone7 phoneA = new Phone7();
Phone7 phoneB = new Phone7();

new Thread(()->{
try {
phoneA.sendEmail();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"A").start();

TimeUnit.SECONDS.sleep(1);
new Thread(()->{
phoneB.callPhone();
},"B").start();
}
}
class Phone7{
public static synchronized void sendEmail() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
System.out.println("sendEmail");
}

public static synchronized void callPhone(){
System.out.println("callPhone");
}
}

场景八

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import java.util.concurrent.TimeUnit;

/**
* 一个被static+synchronized 修饰的方法和普通的synchronized方法,先执行sendEmail()还是callPhone()?
* 答案:callPhone()
* 解释: 只要被static 修饰的锁的就是整个class模板
* 这里一个锁的是class模板 一个锁的是调用者
* 所以锁的是两个对象 互不影响
*/
public class LockDemo8 {
public static void main(String[] args) throws InterruptedException {
Phone8 phoneA = new Phone8();
Phone8 phoneB = new Phone8();

new Thread(()->{
try {
phoneA.sendEmail();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"A").start();

TimeUnit.SECONDS.sleep(1);
new Thread(()->{
phoneB.callPhone();
},"B").start();
}
}
class Phone8{
public static synchronized void sendEmail() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
System.out.println("sendEmail");
}

public synchronized void callPhone(){
System.out.println("callPhone");
}
}

小结:
1、new this 调用的这个对象,是一个具体的对象!
2、static class 唯一的一个模板!
在我们编写多线程程序得时候,只需要搞明白这个到底锁的是什么就不会出错了!synchronized(Demo.class)synchronized(this)

  • Title: 经典8锁问题--助你彻底搞懂锁的概念
  • Author: viEcho
  • Created at : 2021-04-23 19:55:09
  • Updated at : 2024-01-18 14:49:37
  • Link: https://viecho.github.io/2021/0423/8-lock-question.html
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments
On this page
经典8锁问题--助你彻底搞懂锁的概念