可重入锁

1
也叫可递归锁,当同一线程再次进入同步代码时,可以使用自己已获取到的锁;其目的是当同一线程多次获取到的是同一把锁能防止死锁的发生

代码展示

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
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockTest implements Runnable {

private Lock lock = new ReentrantLock();

public void get() {

lock.lock();

System.out.println("get方法的线程id: " + Thread.currentThread().getId());

set();

lock.unlock();

}

public void set() {

lock.lock();

System.out.println("set方法的线程id: " + Thread.currentThread().getId());

lock.unlock();

}

@Override
public void run() {

get();

}

public static void main(String[] args) {

LockTest lockTest = new LockTest();

new Thread(lockTest).start();

new Thread(lockTest).start();

}
}

打印展示

可重入锁

公平锁与非公平锁

公平锁与非公平锁

1
2
3
4
1.公平锁会维护一个等待队列,多个在阻塞状态等待的线程会被插入到等待队列,在调度时是按所发请求的时间顺序获取锁
2.在无需保证先进先出的情况下,可以使用非公平锁去抢占锁
3.非公平锁性能高于公平锁,但是如果当前线程不是队列的第一个线程就无法获取到锁,这样会增加线程的切换次数
4.如果线程占用(处理)时间远长于线程等待时间,那么使用非公平锁的效率就不太明显,但是使用公平锁会增强业务的可控性

公平锁

代码展示

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
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockTest {

/* 公平锁 */
private Lock lock = new ReentrantLock(true);

public void fairLock() {

try {

lock.lock();

System.out.println(Thread.currentThread().getName() + "获得了锁");

} finally {
lock.unlock();
}
}

public static void main(String[] args) {

LockTest lockTest = new LockTest();

Runnable runnable = () -> {

System.out.println(Thread.currentThread().getName() + "启动");

lockTest.fairLock();

};

Thread[] threads = new Thread[10];

for (int i = 0; i < 10; i++) threads[i] = new Thread(runnable);

for (int i = 0; i < 10; i++) threads[i].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
32
33
34
35
36
37
38
39
40
41
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockTest {

/* 非公平锁 */
private Lock lock = new ReentrantLock(false);

public void fairLock() {

try {

lock.lock();

System.out.println(Thread.currentThread().getName() + "获得了锁");

} finally {
lock.unlock();
}
}

public static void main(String[] args) {

LockTest lockTest = new LockTest();

Runnable runnable = () -> {

System.out.println(Thread.currentThread().getName() + "启动");

lockTest.fairLock();

};

Thread[] threads = new Thread[10];

for (int i = 0; i < 10; i++) threads[i] = new Thread(runnable);

for (int i = 0; i < 10; i++) threads[i].start();

}
}

打印展示

非公平锁

读写锁

1
2
3
1.ReentrantReadWriteLock(读写锁)对象会使用两把锁管理临界资源,分别是读锁与写锁
2.某线程获得了资源的读锁,其他读操作可以并发,但写操作的线程会被阻塞
3.当读操作的数量远超过写操作时,可以用读写锁使读操作能够并发执行,从而提升性能

代码展示

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
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class LockTest {

/* 读写锁 */
private final ReadWriteLock lock = new ReentrantReadWriteLock();
/* 读锁 */
private final Lock readLock = lock.readLock();
/* 写锁 */
private final Lock writeLock = lock.writeLock();

private int num;

public void read() {

int i = 0;

while (i++ < 3) {

try {
readLock.lock();
System.out.println(Thread.currentThread().getId() + " 开始读");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getId() + " 读num: " + num);
} catch (Exception e) {
e.printStackTrace();
} finally {
readLock.unlock();
}
}
}

public void write() {

int i = 0;

while (i++ < 3) {

try {
writeLock.lock();
System.out.println(Thread.currentThread().getId() + " 开始写");
Thread.sleep(1000);
num = (int) (Math.random() * 10);
System.out.println(Thread.currentThread().getId() + " 修改后的num: " + num);
} catch (Exception e) {
e.printStackTrace();
} finally {
writeLock.unlock();
}
}
}

public static class ReadThead extends Thread {

private final LockTest lockTest;

public ReadThead(LockTest lockTest) {
this.lockTest = lockTest;
}

@Override
public void run() {
lockTest.read();
}
}

public static class WriteThead extends Thread {

private final LockTest lockTest;

public WriteThead(LockTest lockTest) {
this.lockTest = lockTest;
}

@Override
public void run() {
lockTest.write();
}
}

public static void main(String[] args) {

LockTest lockTest = new LockTest();

for (int i = 0; i < 3; i++) {
new ReadThead(lockTest).start();
new WriteThead(lockTest).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
32
33
34
35
36
37
38
12 开始读
12 读num: 0
13 开始写
13 修改后的num: 5
13 开始写
13 修改后的num: 1
13 开始写
13 修改后的num: 7
15 开始写
15 修改后的num: 5
15 开始写
15 修改后的num: 3
15 开始写
15 修改后的num: 4
14 开始读
16 开始读
14 读num: 4
16 读num: 4
17 开始写
17 修改后的num: 2
17 开始写
17 修改后的num: 3
17 开始写
17 修改后的num: 2
12 开始读
14 开始读
16 开始读
14 读num: 2
16 读num: 2
16 开始读
12 读num: 2
12 开始读
14 开始读
14 读num: 2
16 读num: 2
12 读num: 2

Process finished with exit code 0