(轉)Java 5.0多線程編程(3)
Lock
接口
ReentrantLock
是
Lock
的具體類,
Lock
提供了以下一些方法:
-
lock():
請求鎖定,如果鎖已被別的線程鎖定,調用此方法的線程被阻斷進入等待狀態。
-
tryLock()
:如果鎖沒被別的線程鎖定,進入鎖定狀態,并返回
true
。若鎖已被鎖定,返回
false
,不進入等待狀態。此方法還可帶時間參數,如果鎖在方法執行時已被鎖定,線程將繼續等待規定的時間,若還不行才返回
false
。
-
unlock()
:取消鎖定,需要注意的是
Lock
不會自動取消,編程時必須手動解鎖。
代碼:
//
生成一個鎖
Lock lock = new ReentrantLock();
public void accessProtectedResource() {
? lock.lock(); //
取得鎖定
? try {
??? //
對共享資源進行操作
? } finally {
??? //
一定記著把鎖取消掉,鎖本身是不會自動解鎖的
??? lock.unlock();
? }
} |
ReadWriteLock
接口
?? 為了提高效率有些共享資源允許同時進行多個讀的操作,但只允許一個寫的操作,比如一個文件,只要其內容不變可以讓多個線程同時讀,不必做排他的鎖定,排他的鎖定只有在寫的時候需要,以保證別的線程不會看到數據不完整的文件。
ReadWriteLock
可滿足這種需要。
ReadWriteLock
內置兩個
Lock
,一個是讀的
Lock
,一個是寫的
Lock
。多個線程可同時得到讀的
Lock
,但只有一個線程能得到寫的
Lock
,而且寫的
Lock
被鎖定后,任何線程都不能得到
Lock
。
ReadWriteLock
提供的方法有:
-
readLock():
返回一個讀的
lock
-
writeLock():
返回一個寫的
lock,
此
lock
是排他的。
ReadWriteLock
的例子:
public class FileOperator{
????? //
初始化一個
ReadWriteLock
????? ReadWriteLock lock = new ReentrantReadWriteLock();
public String read() {
????? //
得到
readLock
并鎖定
??????????? Lock readLock = lock.readLock();
??????
?????readLock.lock();
??????????? try {
????????????????? //
做讀的工作
????????????????? return "Read something";
??????????? } finally {
???????????????? readLock.unlock();
??????????? }
????? }
?????
public void write(String content) {
????? //
得到
writeLock
并鎖定
??????????? Lock writeLock = lock.writeLock();
??????????? writeLock.lock();
??????????? try {
????????????????? //
做讀的工作
??????????? } finally {
???????????????? writeLock.unlock();
??????????? }
????? }
} |
?
?? 需要注意的是
ReadWriteLock
提供了一個高效的鎖定機理,但最終程序的運行效率是和程序的設計息息相關的,比如說如果讀的線程和寫的線程同時在等待,要考慮是先發放讀的
lock
還是先發放寫的
lock
。如果寫發生的頻率不高,而且快,可以考慮先給寫的
lock
。還要考慮的問題是如果一個寫正在等待讀完成,此時一個新的讀進來,是否要給這個新的讀發鎖,如果發了,可能導致寫的線程等很久。等等此類問題在編程時都要給予充分的考慮。
Condition
接口:
?? 有時候線程取得
lock
后需要在一定條件下才能做某些工作,比如說經典的
Producer
和
Consumer
問題,
Consumer
必須在籃子里有蘋果的時候才能吃蘋果,否則它必須暫時放棄對籃子的鎖定,等到
Producer
往籃子里放了蘋果后再去拿來吃。而
Producer
必須等到籃子空了才能往里放蘋果,否則它也需要暫時解鎖等
Consumer
把蘋果吃了才能往籃子里放蘋果。在
Java 5.0
以前,這種功能是由
Object
類的
wait(), notify()
和
notifyAll()
等方法實現的,在
5.0
里面,這些功能集中到了
Condition
這個接口來實現,
Condition
提供以下方法:
-
await()
:使調用此方法的線程放棄鎖定,進入睡眠直到被打斷或被喚醒。
-
signal():
喚醒一個等待的線程
-
signalAll()
:喚醒所有等待的線程
Condition
的例子:
public class Basket {?????
Lock lock = new ReentrantLock();
//
產生
Condition
對象
???? Condition produced = lock.newCondition();
???? Condition consumed = lock.newCondition();
???? boolean available = false;
??
??
???? public void produce() throws InterruptedException {
?????????? lock.lock();
?????????? try {
???????????????? if(available){
??????????????????? consumed.await(); //
放棄
lock
進入睡眠
?
???????????????? }
???????????????? /*
生產蘋果
*/
???????????????? System.out.println("Apple produced.");
???????????????? available = true;
???????????????? produced.signal(); //
發信號喚醒等待這個
Condition
的線程
?????????? } finally {
???????????????? lock.unlock();
?????????? }
???? }
????
???? public void consume() throws InterruptedException {
?????????? lock.lock();
?????????? try {
???????????????? if(!available){
?????????????????????? produced.await();//
放棄
lock
進入睡眠
?
???????????????? }
???????????????? /*
吃蘋果
*/
???????????????? System.out.println("Apple consumed.");
???????????????? available = false;
???????????????? consumed.signal();//
發信號喚醒等待這個
Condition
的線程
?????????? } finally {
???????????????? lock.unlock();
?????????? }
???? }?????
} |
ConditionTester:
public class ConditionTester {
?????
????? public static void main(String[] args) throws InterruptedException{
final Basket basket = new Basket();
//
定義一個
producer
??????????? Runnable producer = new Runnable() {
????????????????? public void run() {
??????????????????????? try {
????????????????????????????? basket.produce();
??????
?????????????????} catch (InterruptedException ex) {
????????????????????????????? ex.printStackTrace();
??????????????????????? }
????????????????? }
};
//
定義一個
consumer
??????????? Runnable consumer = new Runnable() {
????????????????? public void run() {
??????????????????????? try {
????????????????????????????? basket.consume();
??????????????????????? } catch (InterruptedException ex) {
????????????????????????????? ex.printStackTrace();
??????????????????????? }
????????????????? }
};
//
各產生
10
個
consumer
和
producer
??????????? ExecutorService service = Executors.newCachedThreadPool();
??????????? for(int i=0; i < 10; i++)
????????????????? service.submit(consumer);
??????????? Thread.sleep(2000);
??????????? for(int i=0; i<10; i++)
????????????????? service.submit(producer);
??????????? service.shutdown();
????? }?????
} |
5: Synchronizer:同步裝置
?? Java 5.0
里新加了
4
個協調線程間進程的同步裝置,它們分別是
Semaphore, CountDownLatch, CyclicBarrier
和
Exchanger.
Semaphore:
?? 用來管理一個資源池的工具,
Semaphore
可以看成是個通行證,線程要想從資源池拿到資源必須先拿到通行證,
Semaphore
提供的通行證數量和資源池的大小一致。如果線程暫時拿不到通行證,線程就會被阻斷進入等待狀態。以下是一個例子:
public class Pool {
???
??ArrayList
????? Semaphore pass = null;
????? public Pool(int size){
??????????? //
初始化資源池
??????????? pool = new ArrayList
??????????? for(int i=0; i
????????????????? pool.add("Resource "+i);
??????????? }
???
????????//Semaphore
的大小和資源池的大小一致
??????????? pass = new Semaphore(size);
????? }
????? public String get() throws InterruptedException{
??????????? //
獲取通行證
,
只有得到通行證后才能得到資源
??????????? pass.acquire();
??????????? return getResource();
????? }
????? public void put(String resource){
??????????? //
歸還通行證,并歸還資源
??????????? pass.release();
??????????? releaseResource(resource);
????? }
???? private synchronized String getResource() {
??????????? String result = pool.get(0);
??????????? pool.remove(0);
??????????? System.out.println("Give out "+result);
??????????? return result;
????? }
????? private synchronized void releaseResource(String resource) {
??????????? System.out.println("return "+resource);
??????????? pool.add(resource);
????? }
} |
SemaphoreTest:
public class SemaphoreTest {
????? public static void main(String[] args){
??????????? final Pool aPool = new Pool(2);
??????????? Runnable worker = new Runnable() {
????????????????? public void run() {
??????????????????????? String resource = null;
???????
????????????????try {
????????????????????????????? //
取得
resource
????????????????????????????? resource = aPool.get();
??????????????????????? } catch (InterruptedException ex) {
????????????????????????????? ex.printStackTrace();
??????????????????????? }
??????????????????????? //
用
resource
做工作
??????????????????????? System.out.println("I worked on "+resource);
??????????????????????? //
歸還
resource
??????????????????????? aPool.put(resource);
????????????????? }
??????????? };
??????????? ExecutorService service = Executors.newCachedThreadPool();
??????????? for(int i=0; i<20; i++){
????????????????? service.submit(worker);
??????????? }
??????????? service.shutdown();
????? }????
} |
posted on 2007-03-26 14:31 advincenting 閱讀(257) 評論(0) 編輯 收藏