重入鎖,顧名思義,就是支持重進入的鎖,它表示該鎖能夠支持一個線程對資源的重復加鎖。重進入是指任意線程在獲取到鎖之后能夠再次獲取該鎖而不會被鎖阻塞,該特性的實現需要解決以下兩個問題。
1、線程再次獲取鎖。鎖需要去識別獲取鎖的線程是否為當前占據鎖的線程,如果是,則再次成功獲取。
2、鎖的最終釋放。線程重復n次獲取了鎖,隨后在第n次釋放該鎖后,其他線程能夠獲取到該鎖。鎖的最終釋放要求鎖對于獲取進行計數自增,計數表示當前鎖被重復獲取的次數,而鎖被釋放時,計數自減,當計數等于0時表示鎖已經成功釋放。
Java里面內置鎖(synchronize)和Lock(ReentrantLock)都是可重入的
synchronized 實例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package com.home; public class SynchronizedTest implements Runnable { public synchronized void method1() { System.out.println( "method1獲得鎖,正常運行!" ); method2(); } public synchronized void method2() { System.out.println( "method2獲得鎖,也正常運行!" ); } @Override public void run() { method1(); } public static void main(String[] args) { SynchronizedTest st = new SynchronizedTest(); new Thread(st).start(); new Thread(st).start(); } } |
Lock 實例
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
|
package com.home; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockTest implements Runnable { Lock lock = new ReentrantLock(); public void method1() { lock.lock(); System.out.println( "method1獲得鎖,正常運行!" ); method2(); lock.unlock(); } public void method2() { lock.lock(); System.out.println( "method2獲得鎖,也正常運行!" ); lock.unlock(); } @Override public void run() { method1(); } public static void main(String[] args) { LockTest lt = new LockTest(); new Thread(lt).start(); new Thread(lt).start(); } } |
兩個例子最后的結果都是正確的,結果如下:
1
2
3
4
|
method1獲得鎖,正常運行! method2獲得鎖,也正常運行! method1獲得鎖,正常運行! method2獲得鎖,也正常運行! |
可重入鎖最大的作用是避免死鎖
讀寫鎖維護了一對相關的鎖,一個用于只讀操作,一個用于寫入操作。只要沒有writer,讀取鎖可以由多個reader線程同時保持。寫入鎖是獨占的。
可重入讀寫鎖 ReentrantReadWriteLock
ReentrantReadWriteLock對象提供了readLock()和writeLock()方法, 用于獲取讀取鎖和寫入鎖.
讀取鎖允許多個reader線程同時持有, 而寫入鎖最多只能有一個writter線程持有.
讀寫鎖的使用場合: 讀取共享數據的頻率遠大于修改共享數據的頻率. 在上述場合下, 使用讀寫鎖控制共享資源的訪問, 可以提高并發性能.
如果一個線程已經持有了寫入鎖, 則可以再持有讀寫鎖. 相反, 如果一個線程已經持有了讀取鎖, 則在釋放該讀取鎖之前, 不能再持有寫入鎖.
可以調用寫入鎖的newCondition()方法獲取與該寫入鎖綁定的Condition對象, 此時與普通的互斥鎖并沒有什么區別. 但是調用讀取鎖的newCondition()方法將拋出異常.
例子
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
|
package com.home; import java.util.Random; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; class ReadWrte { // 共享數據,可以多個線程讀數據,只能有一個線程寫數據 private int data; // 創建讀寫鎖 ReadWriteLock rwLock = new ReentrantReadWriteLock(); /** * 讀數據,上讀鎖 */ public void get() { // 讀鎖 rwLock.readLock().lock(); try { System.out.println(Thread.currentThread().getName() + ",Read!" ); Thread.sleep(( long ) Math.random() * 1000 ); System.out.println(Thread.currentThread().getName() + " 讀出的數據為:" + this .getData()); } catch (Exception e) { e.printStackTrace(); } finally { rwLock.readLock().unlock(); } } /** * 寫數據,上寫鎖 * * @param data */ public void put( int data) { // 寫鎖 rwLock.writeLock().lock(); try { System.out.println(Thread.currentThread().getName() + ",Write!" ); Thread.sleep(( long ) Math.random() * 1000 ); this .setData(data); System.out.println(Thread.currentThread().getName() + " 寫入的數據為:" + this .getData()); } catch (InterruptedException e) { e.printStackTrace(); } finally { rwLock.writeLock().unlock(); } } public int getData() { return data; } public void setData( int data) { this .data = data; } } /** * 測試類 * * @author itmyhome * */ public class ReadWriteLockTest { /** * @param args */ public static void main(String[] args) { // 創建ReadWrte對象 final ReadWrte rw = new ReadWrte(); for ( int i = 0 ; i < 10 ; i++) { // 創建并啟動10個讀線程 new Thread( new Runnable() { @Override public void run() { rw.get(); } }).start(); // 創建并啟動10個寫線程 new Thread( new Runnable() { @Override public void run() { // 寫入一個隨機數 rw.put( new Random().nextInt( 8 )); } }).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
|
Thread- 0 ,Read! Thread- 4 ,Read! Thread- 8 ,Read! Thread- 12 ,Read! Thread- 0 讀出的數據為: 0 Thread- 4 讀出的數據為: 0 Thread- 8 讀出的數據為: 0 Thread- 12 讀出的數據為: 0 Thread- 19 ,Write! Thread- 19 寫入的數據為: 5 Thread- 7 ,Write! Thread- 7 寫入的數據為: 7 Thread- 3 ,Write! Thread- 3 寫入的數據為: 4 Thread- 16 ,Read! Thread- 16 讀出的數據為: 4 Thread- 11 ,Write! Thread- 11 寫入的數據為: 0 Thread- 15 ,Write! Thread- 15 寫入的數據為: 5 Thread- 2 ,Read! Thread- 2 讀出的數據為: 5 Thread- 17 ,Write! Thread- 17 寫入的數據為: 2 Thread- 6 ,Read! Thread- 6 讀出的數據為: 2 Thread- 1 ,Write! Thread- 1 寫入的數據為: 5 Thread- 13 ,Write! Thread- 13 寫入的數據為: 4 Thread- 9 ,Write! Thread- 9 寫入的數據為: 7 Thread- 5 ,Write! Thread- 5 寫入的數據為: 2 Thread- 10 ,Read! Thread- 10 讀出的數據為: 2 Thread- 18 ,Read! Thread- 14 ,Read! Thread- 18 讀出的數據為: 2 Thread- 14 讀出的數據為: 2 |
從圖中我們可以看出,可以多個線程同時讀,但只能一個線程寫,即寫數據和寫入數據一并完成。
總結
以上就是本文關于Java并發編程之重入鎖與讀寫鎖的全部內容,希望對大家有所幫助。歡迎各位參閱本站其他專題,有什么問題可以隨時留言,小編會及時回復大家的。感謝大家對本站的支持。
原文鏈接:http://blog.csdn.net/itmyhome1990/article/details/75309367