synchronized 关键字概述
- Java 平台中的任何一个对象都有唯一一个与之关联的锁。这种锁被称为监视器或者内部锁。
- 内部锁是一种排他锁,它能够保障原子性、可见性和有序性。内部锁是通过 synchronized 关键字实现的。
- synchronized 关键字可以用来修饰方法以及代码块。
- synchronized 关键字修饰的方法就被称为同步方法。
- synchronized 修饰的静态方法就被称为静态同步方法。
- synchronized 修饰的实例方法就被称为实例同步方法。同步方法的整个方法体就是一个临界区。
synchronized 关键字修饰的代码块被称为同步块,其语法如下所示:
注意: 作为锁句柄的变量通常采用 private final 修饰,如:private final Object lock = new Object();
synchronized 实例方法和 synchronized 代码块
假设有如下 synchronized 实例方法。
1
2
|
synchronized void method() {
}
|
这跟下面将方法体用 synchronized 代码块包围起来是等效的。
1
2
3
4
|
void method() {
synchronized (this) {
}
}
|
也就是说,synchronized 实例方法是使用 this 的锁来执行线程的互斥处理的。
synchronized 静态方法和 synchronized 代码块



synchronized 关键字线程八锁

- (1)
- (2)
- (3)
- (4)
- (5)
- (6)
- (7)
- (8)
- (9)
- (10)
- (11)
- (12)
两个普通同步方法,两个 Number 对象?不同步
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
|
public class Test {
public static void main(String[] args) {
Number number1 = new Number();
Number number2 = new Number();
new Thread(() -> {
number1.getOne();
}).start();
new Thread(() -> {
number2.getTwo();
}).start();
}
}
class Number {
public synchronized void getOne() {
System.out.println("one");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
}
public synchronized void getTwo() {
System.out.println("two");
}
}
|
两个静态同步方法,两个 Number 对象?同步
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
|
public class Test {
public static void main(String[] args) {
Number number1 = new Number();
Number number2 = new Number();
new Thread(() -> {
number1.getOne();
}).start();
new Thread(() -> {
number2.getTwo();
}).start();
}
}
class Number {
public static synchronized void getOne() {
System.out.println("one");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
}
public static synchronized void getTwo() {
System.out.println("two");
}
}
|
一个静态同步方法,一个非静态同步方法,两个 Number 对象?不同步
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
|
public class Test {
public static void main(String[] args) {
Number number1 = new Number();
Number number2 = new Number();
new Thread(() -> {
number1.getOne();
}).start();
new Thread(() -> {
number2.getTwo();
}).start();
}
}
class Number {
public static synchronized void getOne() {
System.out.println("one");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
}
public synchronized void getTwo() {
System.out.println("two");
}
}
|
两个静态同步方法,一个 Number 对象?同步
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
|
public class Test {
public static void main(String[] args) {
Number number = new Number();
new Thread(() -> {
number.getOne();
}).start();
new Thread(() -> {
number.getTwo();
}).start();
}
}
class Number {
public static synchronized void getOne() {
System.out.println("one");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
}
public static synchronized void getTwo() {
System.out.println("two");
}
}
|
两个普通同步方法,一个 Number 对象?同步
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
|
public class Test {
public static void main(String[] args) {
Number number = new Number();
new Thread(() -> {
number.getOne();
}).start();
new Thread(() -> {
number.getTwo();
}).start();
}
}
class Number {
public synchronized void getOne() {
System.out.println("one");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
}
public synchronized void getTwo() {
System.out.println("two");
}
}
|
一个静态同步方法,一个非静态同步方法,一个 Number 对象?不同步
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
|
public class Test {
public static void main(String[] args) {
Number number = new Number();
new Thread(() -> {
number.getOne();
}).start();
new Thread(() -> {
number.getTwo();
}).start();
}
}
class Number {
public static synchronized void getOne() {
System.out.println("one");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
}
public synchronized void getTwo() {
System.out.println("two");
}
}
|
一个(静态 or 非静态)同步方法,一个(静态 or 非静态)非同步方法,一个 Number 对象?不同步
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
|
public class Test {
public static void main(String[] args) {
Number number = new Number();
new Thread(() -> {
number.getOne();
}).start();
new Thread(() -> {
number.getTwo();
}).start();
}
}
class Number {
public synchronized void getOne() {
System.out.println("one");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
}
public void getTwo() {
System.out.println("two");
}
}
|
一个(静态 or 非静态)同步方法,一个(静态 or 非静态)非同步方法,两个 Number 对象?不同步
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
|
public class Test {
public static void main(String[] args) {
Number number1 = new Number();
Number number2 = new Number();
new Thread(() -> {
number1.getOne();
}).start();
new Thread(() -> {
number2.getTwo();
}).start();
}
}
class Number {
public synchronized void getOne() {
System.out.println("one");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
}
public void getTwo() {
System.out.println("two");
}
}
|
synchronized 关键字的特点
-
可重入性,当一个线程再次请求自己持有对象锁的临界资源时,这种情况属于重入锁,请求将会成功。
从互斥锁的设计上来说,当一个线程试图操作一个由其他线程持有的对象锁的临界资源时,将会处于阻塞状态,但当一个线程再次请求自己持有对象锁的临界资源时,这种情况属于重入锁,请求将会成功,在 Java 中 synchronized 是基于原子性的内部锁机制,是可重入的,因此在一个线程调用 synchronized 方法的同时在其方法体内部调用该对象另一个 synchronized 方法,也就是说一个线程得到一个对象锁后再次请求该对象锁,是允许的,这就是 synchronized 的可重入性。
-
自动释放锁,当代码段执行结束或出现异常后会自动释放对监视器的锁定。
-
互斥性,被 synchronized 修饰的方法同时只能由一个线程执行。
synchronized 关键字的使用
普通方法和代码块中使用 this 是同一个监视器(锁),即某个具体调用该代码的对象。
静态方法和代码块中使用该类的 class 对象是同一个监视器,任何该类的对象调用该段代码时都是在争夺同一个监视器的锁定。
注意:作为锁句柄的变量通常采用 private final 修饰,如:private final Object lock = new Object();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public class SynchronizedTest implements Runnable {
private static int i = 0;
public static synchronized void increase() {
i++;
}
@Override
public void run() {
for (int j = 0; j < 10000000; j++) {
increase();
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new SynchronizedTest());
Thread t2 = new Thread(new SynchronizedTest());
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
|
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
|
public class SynchronizedTest {
public synchronized void method1() {
System.out.println("Method 1 start");
try {
System.out.println("Method 1 execute");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 1 end");
}
public synchronized void method2() {
System.out.println("Method 2 start");
try {
System.out.println("Method 2 execute");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 2 end");
}
public static void main(String[] args) {
SynchronizedTest test = new SynchronizedTest();
new Thread(test::method1).start();
new Thread(test::method2).start();
}
}
|
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
|
public class SynchronizedTest {
public synchronized void method1() {
System.out.println("Method 1 start");
try {
System.out.println("Method 1 execute");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 1 end");
}
public void method2() {
System.out.println("Method 2 start");
try {
System.out.println("Method 2 execute");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 2 end");
}
public static void main(String[] args) {
SynchronizedTest test = new SynchronizedTest();
new Thread(test::method1).start();
new Thread(test::method2).start();
}
}
|
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
|
public class SynchronizedTest {
public synchronized void method1() {
System.out.println("Method 1 start");
try {
System.out.println("Method 1 execute");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 1 end");
}
public void method2() {
System.out.println("Method 2 start");
try {
System.out.println("Method 2 execute");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 2 end");
}
public static void main(String[] args) {
SynchronizedTest test1 = new SynchronizedTest();
SynchronizedTest test2 = new SynchronizedTest();
new Thread(test1::method1).start();
new Thread(test2::method2).start();
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public class SynchronizedTest implements Runnable {
private static final SynchronizedTest instance = new SynchronizedTest();
private static int i = 0;
@Override
public void run() {
synchronized (instance) {
for (int j = 0; j < 10000000; j++) {
i++;
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
//this锁的是当前实例对象
synchronized (this) {
for (int j = 0; j < 1000000; j++) {
i++;
}
}
//class锁的是当前类对象
synchronized (AccountingSync.class) {
for (int j = 0; j < 1000000; j++) {
i++;
}
}
|
synchronized 关键字常见面试题
synchronized 关键字参考资料
版权声明:
本博客所有文章除特别声明外,均采用
CC BY-NC-SA 4.0
许可协议,转载请注明出处!