0%

java | synchronized 对象锁

synchronized 对象锁,采用互斥的方式让同一时刻至多有一个线程能持有「对象锁」。

其他锁想要获取这个「对象锁」就会被阻塞住。

需要注意

  • 互斥是保证临界区的竞态条件发生,同一时刻只能有一个线程执行临界区代码
  • 同步是由于线程的执行顺序

对象锁

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
package com.redisc;

import lombok.extern.slf4j.Slf4j;

@Slf4j(topic = "c.Test")
public class Test {

static int counter = 0;
static Object Lock = new Object();

public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
synchronized (Lock) {
counter++;
}
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
synchronized (Lock) {
counter--;
}
}
});

t1.start();
t2.start();
t1.join();
t2.join();

log.debug("{}", counter);
}
}

输出

1
17:45:38.434 [main] DEBUG c.Test - 0

使用 synchronized 加锁对象后,任何一个线程在处理临界对象的时候,都需要先请求对象锁。

synchronized 实际上是用对象锁保证了临界区内代码的原子性。临界区内的代码对外是不可分隔的。

面向对象的锁的改进

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
package com.redisc;

import lombok.extern.slf4j.Slf4j;

@Slf4j(topic = "c.Test")
public class Test {

public static void main(String[] args) throws InterruptedException {
Room room = new Room();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
room.decrement();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
room.increment();
}
});

t1.start();
t2.start();
t1.join();
t2.join();

log.debug("{}", room.getCounter());
}
}

class Room {
private int counter = 0;

public void increment() {
synchronized (this) {
counter++;
}
}

public void decrement() {
synchronized (this) {
counter--;
}
}

public int getCounter() {
synchronized (this) {
return this.counter;
}
}
}

输出

1
21:51:10.538 [main] DEBUG c.Test - 0

加在方法

对象方法

加在对象方法上,锁定的是 this。

语法如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Test{
public synchronized void test(){

}
}

等价于

class Test{
public void test(){
synchronized(this){

}
}
}

例子如下

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
package com.redisc;

import lombok.extern.slf4j.Slf4j;

@Slf4j(topic = "c.Test")
public class Test {

public static void main(String[] args) throws InterruptedException {
Room room = new Room();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
room.decrement();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
room.increment();
}
});

t1.start();
t2.start();
t1.join();
t2.join();

log.debug("{}", room.getCounter());
}
}

class Room {
private int counter = 0;

public synchronized void increment() {
counter++;
}

public synchronized void decrement() {
counter--;
}

public synchronized int getCounter() {
return this.counter;
}
}

输出

1
21:55:41.435 [main] DEBUG c.Test - 0

静态方法

语法

1
2
3
4
5
6
7
8
9
10
11
12
13
class Test{
public synchronized static void test(){

}
}
等价于
class Test{
public static void test(){
synchronized(Test.class){

}
}
}
请我喝杯咖啡吧~