synchronized关键字总结

synchronized关键字的作用:使同一时刻,只有一个线程能够执行某段代码,另一个线程必须等待当前线程执行完这个代码以后才能执行该段代码。

synchronized 锁的对象四种:

  1. 整个对象:所有获取该对象锁的代码块同一时刻只能由一个线程执行。
  2. 整个类对象:所有获取该类对象锁的代码块同一时刻只能由一个线程执行。
  3. 某个 Field:所有获取该对象这个 Field 锁的代码块同一时刻只能由一个线程执行。
  4. 某个 static Field:所有获取该类这个 static Field 锁的代码块同一时刻只能由一个线程执行。

synchronized使用方式有两种:

  1. 修饰方法
    synchronized修饰方法又分成两种:

    1. 修饰非静态方法,锁的对象是 整个对象

      synchronized void fun(){}

    2. 修饰静态方法,锁的对象是 整个类对象

      synchronized static void fun(){}

      因此修饰方法只能完成synchronized功能的前两个。

  2. 修饰代码块
    synchronized修饰方法能实现全部四种synchronized功能

    1. 修饰对象,这种方式和修饰非静态方法作用相同,都是锁住SynchronizedTest对象。

      synchronized(SynchronizedTest.this){//...}

    2. 修饰类的.class,这种方式和修饰静态方法作用相同,都是锁住SynchronizedTest类对象。

      synchronized(SynchronizedTest.class){//...}

    3. 修饰类的 Field,锁住当前对象的该 Field。

      synchronized(field){//...}

    4. 修饰类的 static Field,锁住类的 static Field。

      synchronized(field){//...}

测试代码:

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
public class SynchronizedTest {
private Object field = new Object();
private static Object staticField = new Object();
//① 修饰非静态方法,取得对象锁:同一时刻只能由同一线程执行 ①和③
synchronized void syncFun() throws InterruptedException {
System.out.println("① syncFun before");
Thread.sleep(1000);
System.out.println("① syncFun after");
}
//② 修饰静态方法,取得类锁:同一时刻只能由同一线程执行 ②和④
synchronized static void staticFun() throws InterruptedException {
System.out.println("② staticFun before");
Thread.sleep(2000);
System.out.println("② staticFun after");
}
//③ 修饰代码块,取得对象锁:同一时刻只能由同一线程执行 ①和③
void syncObjectBlock() throws InterruptedException {
synchronized (this) {
System.out.println("③ syncObjectBlock before");
System.out.println("③ syncObjectBlock after");
}
}
//④ 修饰代码块,取得类锁:同一时刻只能由同一线程执行 ②和④
void staticClassBlock() throws InterruptedException {
synchronized (SynchronizedTest.class) {
System.out.println("④ staticClass before");
System.out.println("④ staticClass after");
}
}
//⑤ 修饰代码块,取得当前对象的field锁:同一时刻只能由同一线程执行 ⑤和⑥
public void syncFieldBlock1() throws InterruptedException {
synchronized (field) {
System.out.println("⑤ field1 before");
Thread.sleep(3000);
System.out.println("⑤ field1 after");
}
}
//⑥ 修饰代码块,取得当前对象的field锁:同一时刻只能由同一线程执行 ⑤和⑥
public void syncFieldBlock2() throws InterruptedException {
synchronized (field) {
System.out.println("⑥ field2 before");
System.out.println("⑥ field2 after");
}
}
//⑦ 修饰代码块,取得类的staticField锁:同一时刻只能由同一线程执行 ⑦和⑧
public void syncStaticFieldBlock1() throws InterruptedException {
synchronized (staticField) {
System.out.println("⑦ staticField1 before");
Thread.sleep(4000);
System.out.println("⑦ staticField1 after");
}
}
//⑧ 修饰代码块,取得类的staticField锁:同一时刻只能由同一线程执行 ⑦和⑧
public void syncStaticFieldBlock2() {
synchronized (staticField) {
System.out.println("⑧ staticField2 before");
System.out.println("⑧ staticField2 after");
}
}
public static void main(String[] args) {
SynchronizedTest test = new SynchronizedTest();
new Thread(new Runnable() {
@Override
public void run() {
try {
test.syncFun();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
SynchronizedTest.staticFun();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
test.syncObjectBlock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
test.staticClassBlock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
test.syncFieldBlock1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
test.syncFieldBlock2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
test.syncStaticFieldBlock1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
test.syncStaticFieldBlock2();
}
}).start();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//输出
① syncFun before
② staticFun before
⑤ field1 before
⑦ staticField1 before
① syncFun after
③ syncObjectBlock before
③ syncObjectBlock after
② staticFun after
④ staticClass before
④ staticClass after
⑤ field1 after
⑥ field2 before
⑥ field2 after
⑦ staticField1 after
⑧ staticField2 before
⑧ staticField2 after

可以看到,③④⑥⑧的代码都没有设置 Thread.sleep(),但是因为有另一个线程正在执行它们修饰的代码所锁的对象的其他代码,导致它们无法立刻执行代码,等到另一个线程释放相应锁才能执行。