Lock是java.util.concurrent.locks包下的接口,Lock 實現(xiàn)提供了比使用synchronized 方法和語句可獲得的更廣泛的鎖定操作,它能以更優(yōu)雅的方式處理線程同步問題,我們拿Java線程之線程同步synchronized和volatile詳解中的一個例子簡單的實現(xiàn)一下和sychronized一樣的效果,代碼如下:
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 LockTest { public static void main(String[] args) { final Outputter1 output = new Outputter1(); new Thread() { public void run() { output.output( "zhangsan" ); }; }.start(); new Thread() { public void run() { output.output( "lisi" ); }; }.start(); } } class Outputter1 { private Lock lock = new ReentrantLock(); // 鎖對象 public void output(String name) { // TODO 線程輸出方法 lock.lock(); // 得到鎖 try { for ( int i = 0 ; i < name.length(); i++) { System.out.print(name.charAt(i)); } } finally { lock.unlock(); // 釋放鎖 } } } |
這樣就實現(xiàn)了和sychronized一樣的同步效果,需要注意的是,用sychronized修飾的方法或者語句塊在代碼執(zhí)行完之后鎖自動釋放,而用Lock需要我們手動釋放鎖,所以為了保證鎖最終被釋放(發(fā)生異常情況),要把互斥區(qū)放在try內(nèi),釋放鎖放在finally內(nèi)。
如果說這就是Lock,那么它不能成為同步問題更完美的處理方式,下面要介紹的是讀寫鎖(ReadWriteLock),我們會有一種需求,在對數(shù)據(jù)進行讀寫的時候,為了保證數(shù)據(jù)的一致性和完整性,需要讀和寫是互斥的,寫和寫是互斥的,但是讀和讀是不需要互斥的,這樣讀和讀不互斥性能更高些,來看一下不考慮互斥情況的代碼原型:
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
|
public class ReadWriteLockTest { public static void main(String[] args) { final Data data = new Data(); for ( int i = 0 ; i < 3 ; i++) { new Thread( new Runnable() { public void run() { for ( int j = 0 ; j < 5 ; j++) { data.set( new Random().nextInt( 30 )); } } }).start(); } for ( int i = 0 ; i < 3 ; i++) { new Thread( new Runnable() { public void run() { for ( int j = 0 ; j < 5 ; j++) { data.get(); } } }).start(); } } } class Data { private int data; // 共享數(shù)據(jù) public void set( int data) { System.out.println(Thread.currentThread().getName() + "準備寫入數(shù)據(jù)" ); try { Thread.sleep( 20 ); } catch (InterruptedException e) { e.printStackTrace(); } this .data = data; System.out.println(Thread.currentThread().getName() + "寫入" + this .data); } public void get() { System.out.println(Thread.currentThread().getName() + "準備讀取數(shù)據(jù)" ); try { Thread.sleep( 20 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "讀取" + this .data); } } |
部分輸出結(jié)果:
1
2
3
4
5
6
7
8
9
10
|
Thread- 1 準備寫入數(shù)據(jù) Thread- 3 準備讀取數(shù)據(jù) Thread- 2 準備寫入數(shù)據(jù) Thread- 0 準備寫入數(shù)據(jù) Thread- 4 準備讀取數(shù)據(jù) Thread- 5 準備讀取數(shù)據(jù) Thread- 2 寫入 12 Thread- 4 讀取 12 Thread- 5 讀取 5 Thread- 1 寫入 12 |
我們要實現(xiàn)寫入和寫入互斥,讀取和寫入互斥,讀取和讀取互斥,在set和get方法加入sychronized修飾符:
1
2
|
public synchronized void set( int data) {...} public synchronized void get() {...} |
部分輸出結(jié)果:
1
2
3
4
5
6
7
8
9
10
|
Thread- 0 準備寫入數(shù)據(jù) Thread- 0 寫入 9 Thread- 5 準備讀取數(shù)據(jù) Thread- 5 讀取 9 Thread- 5 準備讀取數(shù)據(jù) Thread- 5 讀取 9 Thread- 5 準備讀取數(shù)據(jù) Thread- 5 讀取 9 Thread- 5 準備讀取數(shù)據(jù) Thread- 5 讀取 9 |
我們發(fā)現(xiàn),雖然寫入和寫入互斥了,讀取和寫入也互斥了,但是讀取和讀取之間也互斥了,不能并發(fā)執(zhí)行,效率較低,用讀寫鎖實現(xiàn)代碼如下:
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
|
class Data { private int data; // 共享數(shù)據(jù) private ReadWriteLock rwl = new ReentrantReadWriteLock(); public void set( int data) { rwl.writeLock().lock(); // 取到寫鎖 try { System.out.println(Thread.currentThread().getName() + "準備寫入數(shù)據(jù)" ); try { Thread.sleep( 20 ); } catch (InterruptedException e) { e.printStackTrace(); } this .data = data; System.out.println(Thread.currentThread().getName() + "寫入" + this .data); } finally { rwl.writeLock().unlock(); // 釋放寫鎖 } } public void get() { rwl.readLock().lock(); // 取到讀鎖 try { System.out.println(Thread.currentThread().getName() + "準備讀取數(shù)據(jù)" ); try { Thread.sleep( 20 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "讀取" + this .data); } finally { rwl.readLock().unlock(); // 釋放讀鎖 } } } |
部分輸出結(jié)果:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
Thread- 4 準備讀取數(shù)據(jù) Thread- 3 準備讀取數(shù)據(jù) Thread- 5 準備讀取數(shù)據(jù) Thread- 5 讀取 18 Thread- 4 讀取 18 Thread- 3 讀取 18 Thread- 2 準備寫入數(shù)據(jù) Thread- 2 寫入 6 Thread- 2 準備寫入數(shù)據(jù) Thread- 2 寫入 10 Thread- 1 準備寫入數(shù)據(jù) Thread- 1 寫入 22 Thread- 5 準備讀取數(shù)據(jù) |
從結(jié)果可以看出實現(xiàn)了我們的需求,這只是鎖的基本用法,鎖的機制還需要繼續(xù)深入學(xué)習(xí)。
總結(jié)
以上就是本文關(guān)于Java線程之鎖對象Lock-同步問題更完美的處理方式代碼實例的全部內(nèi)容,希望對大家有所幫助,有什么問題可以隨時留言,小編會及時回復(fù)大家的。感謝朋友們對本站的支持!
原文鏈接:http://blog.csdn.net/ghsau/article/details/7461369