顺便总结了几点synchronized和ReentrantLock的区别:
synchronized是JVM层次的锁实现,ReentrantLock是JDK层次的锁实现;
synchronized的锁状态是无法在代码中直接判断的,但是ReentrantLock可以通过
ReentrantLock#isLocked判断;
synchronized是非公平锁,ReentrantLock是可以是公平也可以是非公平的;
synchronized是不可以被中断的,而ReentrantLock#lockInterruptibly方法是可以
被中断的;
在发生异常时synchronized会自动释放锁,而ReentrantLock需要开发者在finally
块中显示释放锁;
ReentrantLock获取锁的形式有多种:如立即返回是否成功的tryLock(),以及等待指
定时长的获取,更加灵活;
synchronized在特定的情况下对于已经在等待的线程是后来的线程先获得锁(回顾
一下sychronized的唤醒策略),而ReentrantLock对于已经在等待的线程是先来的线程
先获得锁;
ReentrantLock 的使用
同步执行,类似于synchronized
1 ReentrantLock lock = new ReentrantLock (); // 参数默认 false ,不公平锁
2 ReentrantLock lock = new ReentrantLock ( true ); // 公平锁
3
4 // 加锁
5 lock . lock ();
6 try {
7 // 临界区
8 } finally {
9 // 解锁
10 lock . unlock ();
11 }
测试
1 public class ReentrantLockDemo {
2
3 private static int sum = 0 ;
4 private static Lock lock = new ReentrantLock ();
5
6 public static void main ( String [] args ) throws InterruptedException {
7
8 for ( int i = 0 ; i < 3 ; i ++ ) {
9 Thread thread = new Thread (() ‐> {
10 // 加锁
11 lock . lock ();
12 try {
13 for ( int j = 0 ; j < 10000 ; j ++ ) {
14 sum ++ ;
15 }
16 } finally {
17 // 解锁
18 lock . unlock ();
19 }
20 });
21 thread . start ();
22 }
23 Thread . sleep ( 2000 );
24 System . out . println ( sum );
25 }
26 }
可重入
1 @Slf4j
2 public class ReentrantLockDemo2 {
3
4 public static ReentrantLock lock = new ReentrantLock ();
5
6 public static void main ( String [] args ) {
7 method1 ();
8 }
9
10
11 public static void method1 () {
12 lock . lock ();
13 try {
14 log . debug ( "execute method1" );
15 method2 ();
16 } finally {
17 lock . unlock ();
18 }
19 }
20 public static void method2 () {
21 lock . lock ();
22 try {
23 log . debug ( "execute method2" );
24 method3 ();
25 } finally {
26 lock . unlock ();
27 }
28 }
29 public static void method3 () {
30 lock . lock ();
31 try {
32 log . debug ( "execute method3" );
33 } finally {
34 lock . unlock ();
35 }
36 }
37 }
可中断
1 @Slf4j
2 public class ReentrantLockDemo3 { 3
4 public static void main ( String [] args ) {
5 ReentrantLock lock = new ReentrantLock ();
6
7 Thread t1 = new Thread (() ‐> {
8
9 log . debug ( "t1 启动 ..." );
10
11 try {
12 lock . lockInterruptibly ();
13 try {
14 log . debug ( "t1 获得了锁 " );
15 } finally {
16 lock . unlock ();
17 }
18 } catch ( InterruptedException e ) {
19 e . printStackTrace ();
20 log . debug ( "t1 等锁的过程中被中断 " );
21 }
22
23 }, "t1" );
24
25 lock . lock ();
26 try {
27 log . debug ( "main 线程获得了锁 " );
28 t1 . start ();
29 // 先让线程 t1 执行
30 try {
31 Thread . sleep ( 1000 );
32 } catch ( InterruptedException e ) {
33 e . printStackTrace ();
34 }
35 t1 . interrupt ();
36 log . debug ( " 线程 t1 执行中断 " );
37 } finally {
38 lock . unlock ();
39 }
40 }
41 }
锁超时
立即失败 1 @Slf4j
2 public class ReentrantLockDemo4 {
3
4 public static void main ( String [] args ) {
5 ReentrantLock lock = new ReentrantLock ();
6
7 Thread t1 = new Thread (() ‐> {
8
9 log . debug ( "t1 启动 ..." );
10 // 注意: 即使是设置的公平锁,此方法也会立即返回获取锁成功或失败,公平策略不生效
11 if ( ! lock . tryLock ()) {
12 log . debug ( "t1 获取锁失败,立即返回 false" );
13 return ;
14 }
15 try {
16 log . debug ( "t1 获得了锁 " );
17 } finally {
18 lock . unlock ();
19 }
20
21 }, "t1" );
22
23
24 lock . lock ();
25 try {
26 log . debug ( "main 线程获得了锁 " );
27 t1 . start ();
28 // 先让线程 t1 执行
29 try {
30 Thread . sleep ( 1000 );
31 } catch ( InterruptedException e ) {
32 e . printStackTrace ();
33 }
34 } finally {
35 lock . unlock ();
36 }
37
38 }
39
40 }
超时失败
1 @Slf4j 2 public class ReentrantLockDemo4 {
3
4 public static void main ( String [] args ) {
5 ReentrantLock lock = new ReentrantLock ();
6 Thread t1 = new Thread (() ‐> {
7 log . debug ( "t1 启动 ..." );
8 // 超时
9 try {
10 if ( ! lock . tryLock ( 1 , TimeUnit . SECONDS )) {
11 log . debug ( " 等待 1s 后获取锁失败,返回 " );
12 return ;
13 }
14 } catch ( InterruptedException e ) {
15 e . printStackTrace ();
16 return ;
17 }
18 try {
19 log . debug ( "t1 获得了锁 " );
20 } finally {
21 lock . unlock ();
22 }
23
24 }, "t1" );
25
26
27 lock . lock ();
28 try {
29 log . debug ( "main 线程获得了锁 " );
30 t1 . start ();
31 // 先让线程 t1 执行
32 try {
33 Thread . sleep ( 2000 );
34 } catch ( InterruptedException e ) {
35 e . printStackTrace ();
36 }
37 } finally {
38 lock . unlock ();
39 }
40
41 }
42
43 }
公平锁
ReentrantLock 默认是不公平的
1 @Slf4j
2 public class ReentrantLockDemo5 {
3
4 public static void main ( String [] args ) throws InterruptedException {
5 ReentrantLock lock = new ReentrantLock ( true ); // 公平锁
6
7 for ( int i = 0 ; i < 500 ; i ++ ) {
8 new Thread (() ‐> {
9 lock . lock ();
10 try {
11 try {
12 Thread . sleep ( 10 );
13 } catch ( InterruptedException e ) {
14 e . printStackTrace ();
15 }
16 log . debug ( Thread . currentThread (). getName () + " running..." );
17 } finally {
18 lock . unlock ();
19 }
20 }, "t" + i ). start ();
21 }
22 // 1s 之后去争抢锁
23 Thread . sleep ( 1000 );
24
25 for ( int i = 0 ; i < 500 ; i ++ ) {
26 new Thread (() ‐> {
27 lock . lock ();
28 try {
29 log . debug ( Thread . currentThread (). getName () + " running..." );
30 } finally {
31 lock . unlock ();
32 }
33 }, " 强行插入 " + i ). start ();
34 }
35 }
36 }
思考: ReentrantLock公平锁和非公平锁的性能谁更高? 条件变量
java.util.concurrent类库中提供Condition类来实现线程之间的协调。调用
Condition.await() 方法使线程等待,其他线程调用Condition.signal() 或
Condition.signalAll() 方法唤醒等待的线程。
注意: 调用Condition的await()和signal()方法,都必须在lock保护之内。
1 @Slf4j
2 public class ReentrantLockDemo6 {
3 private static ReentrantLock lock = new ReentrantLock ();
4 private static Condition cigCon = lock . newCondition ();
5 private static Condition takeCon = lock . newCondition ();
6
7 private static boolean hashcig = false ;
8 private static boolean hastakeout = false ;
9
10 // 送烟
11 public void cigratee (){
12 lock . lock ();
13 try {
14 while ( ! hashcig ){
15 try {
16 log . debug ( " 没有烟,歇一会 " );
17 cigCon . await ();
18
19 } catch ( Exception e ){
20 e . printStackTrace ();
21 }
22 }
23 log . debug ( " 有烟了,干活 " );
24 } finally {
25 lock . unlock ();
26 }
27 }
28
29 // 送外卖
30 public void takeout (){
31 lock . lock ();
32 try {
33 while ( ! hastakeout ){
34 try {
35 log . debug ( " 没有饭,歇一会 " );
36 takeCon . await (); 37
38 } catch ( Exception e ){
39 e . printStackTrace ();
40 }
41 }
42 log . debug ( " 有饭了,干活 " );
43 } finally {
44 lock . unlock ();
45 }
46 }
47
48 public static void main ( String [] args ) {
49 ReentrantLockDemo6 test = new ReentrantLockDemo6 ();
50 new Thread (() ‐> {
51 test . cigratee ();
52 }). start ();
53
54 new Thread (() ‐> {
55 test . takeout ();
56 }). start ();
57
58 new Thread (() ‐> {
59 lock . lock ();
60 try {
61 hashcig = true ;
62 // 唤醒送烟的等待线程
63 cigCon . signal ();
64 } finally {
65 lock . unlock ();
66 }
67
68
69 }, "t1" ). start ();
70
71 new Thread (() ‐> {
72 lock . lock ();
73 try {
74 hastakeout = true ;
75 // 唤醒送饭的等待线程
76 takeCon . signal ();
77 } finally {
78 lock . unlock (); 79 }
80 }, "t2" ). start ();
81 }
82
83 }