Lock是java.util.concurrent.locks包下的接口,Lock 實(shí)現(xiàn)提供了比使用synchronized 方法和語(yǔ)句可獲得的更廣泛的鎖定操作,它能以更優(yōu)雅的方式處理線程同步問(wèn)題,我們拿Java線程之線程同步synchronized和volatile詳解中的一個(gè)例子簡(jiǎn)單的實(shí)現(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(); // 鎖對(duì)象 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(); // 釋放鎖 } } } |
這樣就實(shí)現(xiàn)了和sychronized一樣的同步效果,需要注意的是,用sychronized修飾的方法或者語(yǔ)句塊在代碼執(zhí)行完之后鎖自動(dòng)釋放,而用Lock需要我們手動(dòng)釋放鎖,所以為了保證鎖最終被釋放(發(fā)生異常情況),要把互斥區(qū)放在try內(nèi),釋放鎖放在finally內(nèi)。
如果說(shuō)這就是Lock,那么它不能成為同步問(wèn)題更完美的處理方式,下面要介紹的是讀寫鎖(ReadWriteLock),我們會(huì)有一種需求,在對(duì)數(shù)據(jù)進(jìn)行讀寫的時(shí)候,為了保證數(shù)據(jù)的一致性和完整性,需要讀和寫是互斥的,寫和寫是互斥的,但是讀和讀是不需要互斥的,這樣讀和讀不互斥性能更高些,來(lái)看一下不考慮互斥情況的代碼原型:
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() + "準(zhǔn)備寫入數(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() + "準(zhǔn)備讀取數(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 準(zhǔn)備寫入數(shù)據(jù) Thread- 3 準(zhǔn)備讀取數(shù)據(jù) Thread- 2 準(zhǔn)備寫入數(shù)據(jù) Thread- 0 準(zhǔn)備寫入數(shù)據(jù) Thread- 4 準(zhǔn)備讀取數(shù)據(jù) Thread- 5 準(zhǔn)備讀取數(shù)據(jù) Thread- 2 寫入 12 Thread- 4 讀取 12 Thread- 5 讀取 5 Thread- 1 寫入 12 |
我們要實(shí)現(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 準(zhǔn)備寫入數(shù)據(jù) Thread- 0 寫入 9 Thread- 5 準(zhǔn)備讀取數(shù)據(jù) Thread- 5 讀取 9 Thread- 5 準(zhǔn)備讀取數(shù)據(jù) Thread- 5 讀取 9 Thread- 5 準(zhǔn)備讀取數(shù)據(jù) Thread- 5 讀取 9 Thread- 5 準(zhǔn)備讀取數(shù)據(jù) Thread- 5 讀取 9 |
我們發(fā)現(xiàn),雖然寫入和寫入互斥了,讀取和寫入也互斥了,但是讀取和讀取之間也互斥了,不能并發(fā)執(zhí)行,效率較低,用讀寫鎖實(shí)現(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() + "準(zhǔn)備寫入數(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() + "準(zhǔn)備讀取數(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 準(zhǔn)備讀取數(shù)據(jù) Thread- 3 準(zhǔn)備讀取數(shù)據(jù) Thread- 5 準(zhǔn)備讀取數(shù)據(jù) Thread- 5 讀取 18 Thread- 4 讀取 18 Thread- 3 讀取 18 Thread- 2 準(zhǔn)備寫入數(shù)據(jù) Thread- 2 寫入 6 Thread- 2 準(zhǔn)備寫入數(shù)據(jù) Thread- 2 寫入 10 Thread- 1 準(zhǔn)備寫入數(shù)據(jù) Thread- 1 寫入 22 Thread- 5 準(zhǔn)備讀取數(shù)據(jù) |
從結(jié)果可以看出實(shí)現(xiàn)了我們的需求,這只是鎖的基本用法,鎖的機(jī)制還需要繼續(xù)深入學(xué)習(xí)。
總結(jié)
以上就是本文關(guān)于Java線程之鎖對(duì)象Lock-同步問(wèn)題更完美的處理方式代碼實(shí)例的全部?jī)?nèi)容,希望對(duì)大家有所幫助,有什么問(wèn)題可以隨時(shí)留言,小編會(huì)及時(shí)回復(fù)大家的。感謝朋友們對(duì)本站的支持!
原文鏈接:http://blog.csdn.net/ghsau/article/details/7461369