synchronized锁的使用

synchronized可以使用在方法和代码块中, 使用的方式不同锁代表的含义不同, 下面将从几个方面进行介绍.

  • 普通方法
  • 静态方法
  • 代码块synchronized(this)
  • 代码块synchronized(*.class)

结论

  • 在使用synchronized关键字中锁主要分为两类, 一种是对象锁, 另一种类锁
  • 普通加锁方法和synchronized(this)都是对象锁, 静态加锁方法和synchronized(*.class)都是类锁
  • 对象锁: 同一对象持有锁, 相同对象等待, 其他对象不受影响; 不同对象持有锁, 互不影响.
  • 类锁: 类锁时, 只要该类的对象持有锁, 无论是否为同一对象访问静态同步方法时都等待, 访问非静态同步方法不受影响.
  • 对象锁和类锁互相不影响

测试代码及过程

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
package com.liuzhihang.tool.sync;

/**
* @author liuzhihang
* @date 2018/7/11 16:25
*/
public class SyncMainTest {

public static void main(String[] args) {
SyncTest syncTest1 = new SyncTest();
// SyncTest syncTest2 = new SyncTest();
new Thread(() -> syncTest1.methodA(), "线程 01 ").start();
new Thread(() -> syncTest1.methodB(), "线程 02 ").start();

}
}


class SyncTest {

void methodA() {

System.out.println(Thread.currentThread().getName() + "start");
try {
System.out.println(Thread.currentThread().getName() + "sleep");
Thread.sleep(500);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName() + "end");
}

void methodB() {

System.out.println(Thread.currentThread().getName() + "start");
try {
System.out.println(Thread.currentThread().getName() + "sleep");
Thread.sleep(300);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName() + "end");
}

}

以上为一个简单的测试代码, 指使用两个线程分别调用两个方法, 通过打印结果可以看出顺序是乱序的, 其中线程的 start() 顺序并不代表线程的执行顺序, 在下面测试中假设是 “线程01” 先执行.

1.A B 方法分别添加synchronized关键字 + 同一对象

1
2
3
4
5
6
7
8
9
class SyncTest {
synchronized void methodA() {
// ...
}
synchronized void methodB() {
// ...
}

}

结论: 方法 A 阻塞, 方法 B 等待 A 执行完毕后才继续执行.

2.A B 方法分别添加synchronized关键字 + 不同对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class SyncMainTest {

public static void main(String[] args) {
SyncTest syncTest1 = new SyncTest();
SyncTest syncTest2 = new SyncTest();
new Thread(() -> syncTest1.methodA(), "线程 01 ").start();
new Thread(() -> syncTest2.methodB(), "线程 02 ").start();

}
}
class SyncTest {
synchronized void methodA() {
// ...
}
synchronized void methodB() {
// ...
}

}

结论: 方法 A 阻塞, 方法 B 不受影响.

3.A 方法分别添加synchronized关键字 B方法不添加

1
2
3
4
5
6
7
8
9
class SyncTest {
synchronized void methodA() {
// ...
}
void methodB() {
// ...
}

}

结论: 方法 A 阻塞, 方法 B 不受影响.

4.A B 方法分别添加 static synchronized + 不同对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class SyncMainTest {

public static void main(String[] args) {
SyncTest syncTest1 = new SyncTest();
SyncTest syncTest2 = new SyncTest();
new Thread(() -> syncTest1.methodA(), "线程 01 ").start();
new Thread(() -> syncTest2.methodB(), "线程 02 ").start();

}
}
class SyncTest {
static synchronized void methodA() {
// ...
}
static synchronized void methodB() {
// ...
}

}

结论: 方法 A 阻塞, 方法 B 等待 A结束后继续执行.

5.A 方法添加 static synchronized, B 方法添加 synchronized + 不同对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class SyncMainTest {

public static void main(String[] args) {
SyncTest syncTest1 = new SyncTest();
SyncTest syncTest2 = new SyncTest();
new Thread(() -> syncTest1.methodA(), "线程 01 ").start();
new Thread(() -> syncTest2.methodB(), "线程 02 ").start();

}
}
class SyncTest {
static synchronized void methodA() {
// ...
}
synchronized void methodB() {
// ...
}

}

结论: 方法 A 阻塞, 方法 B 不受影响.

6.A B 方法内添加 synchronized(this)

1
2
3
4
5
6
7
8
9
10
11
12
13
class SyncTest {
void methodA() {
synchronized (this) {
// ...
}
}
void methodB() {
synchronized (this) {
// ...
}
}

}

结论: 同一对象 A 阻塞 B等待, 不同对象 A阻塞 B不受影响

7.A B 方法内添加 synchronized(SyncTest.class)

1
2
3
4
5
6
7
8
9
10
11
12
13
class SyncTest {
void methodA() {
synchronized (SyncTest.class) {
// ...
}
}
void methodB() {
synchronized (SyncTest.class) {
// ...
}
}

}

结论: 同一/不同对象 A 阻塞 B等待

8.A 方法内添加 synchronized(SyncTest.class), B 方法内添加 synchronized(this)

1
2
3
4
5
6
7
8
9
10
11
12
13
class SyncTest {
void methodA() {
synchronized (SyncTest.class) {
// ...
}
}
void methodB() {
synchronized (this) {
// ...
}
}

}

结论: 同一/不同对象 A 阻塞 B不受影响

9.A 方法内添加 synchronized(SyncTest.class), B 方法内添加 synchronized(OtherObj)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class SyncTest {

private String string = "lock";

void methodA() {
synchronized (SyncTest.class) {
// ...
}
}
void methodB() {
synchronized (string) {
// ...
}
}

}

结论: 同一/不同对象 A 阻塞 B不受影响