Java併發程式設計之執行緒管理(高階執行緒同步7)
3執行緒同步實用程式
在這一節中,我們將討論如何使用高級別機制去獲得多執行緒的同步(synchronized)。這些高級別機制有下面幾種:
Ø 訊號(Semaphores):一個訊號就是一個計數器,它控制著對於一個或者多個共享資源的訪問。這個機制是併發程式設計的基本工具,在大多數程式語言中都提供這樣的機制。
Ø 倒計時彈簧鎖:CountDownLatch類是Java語言提供的一種機制,允許一個執行緒去等待多個操作行為的結束。
Ø 迴圈阻塞器:CyclicBarrier類是Java語言提供的一種機制,允許在一個普通點上同步多個執行緒。
Ø 分階分離器(Phaser):Phaser類是Java API 7語言中提供的一種機制。它控制著併發程式在多個階段來執行。這是Java API 7 中的新特性。
Ø 交換器(Exchanger):交換器類是Java語言提供的另外的機制,提供給兩個執行緒一個交換資料點。
3.1 控制併發地訪問一個資源
Semaphore類有兩個 acquire()方法的另外版本:
1. acqureUninterruptibly():當這個內部的計數器的訊號為0,阻塞這個執行緒直到這個訊號被釋放。在這個阻塞時間內,執行緒可能會被中斷。然後,這個方法報出InterruptedException異常。這個版本的acquire將忽略掉執行緒的中斷,不會報出任何異常。
2. tryAcqure():這個方法將嘗試著獲取訊號(semaphore)。如果它獲得了,這個方法返回true值。但是,如果它不能夠,這個方法返回false值,而不會被阻塞並等待訊號的釋放。程式設計師負責根據這個返回值而定義正確的業務邏輯。
下面列舉一個例子,說明semaphore的使用。例子中定義列印佇列服務,多執行緒PrintJob呼叫列印服務。
定義PrintQueueTask類:
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/**
* This class implements thePrintQueue using a Semaphore to control the
* access to it.
*
*/
public class PrintQueueTask {
/**
* Semaphore to control the access to the queue
*/
private finalSemaphore semaphore;
/**
* Constructor of the class. Initializes thesemaphore
*/
public PrintQueueTask(){
semaphore=new Semaphore(1);
}
/**
* Method that simulates printing a document
* @param document Document to print
*/
public voidprintJob (Object document){
try {
// Get the access to the semaphore. If other job is printing, this
// thread sleep until get the access to the semaphore
semaphore.acquire();
Long duration=(long)(Math.random()*5);
System.out.printf("%s: PrintQueuesTask: Printing a Job during %d seconds\n",Thread.currentThread().getName(),duration);
Thread.sleep(duration);
TimeUnit.SECONDS.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// Free the semaphore. If there are other threads waiting for thissemaphore,
// the JVM selects one of this threads and give it the access.
semaphore.release();
}
}
}
定義執行類PrintJob:
/**
* This class simulates a job thatsend a document to print.
*
*/
public class PrintJob implements Runnable {
/**
* Queue to print the documents
*/
private PrintQueueTask printQueueTask;
/**
* Constructor of the class. Initializes thequeue
* @param printQueueTask
*/
public PrintJob(PrintQueueTask printQueueTask){
this.printQueueTask=printQueueTask;
}
/**
* Core method of the Job. Sends the documentto the print queue and waits
* forits finalization
*/
@Override
public void run() {
System.out.printf("%s: Going to print a job\n",Thread.currentThread().getName());
printQueueTask.printJob(new Object());
System.out.printf("%s: The document has been printed\n",Thread.currentThread().getName());
}/**
* Main method of the class. Run ten jobs inparallel that
* send documents to the print queue at thesame time.
*/
public static void main (String args[]){
// Creates the print queue
PrintQueueTask printQueue=new PrintQueueTask();
// Creates ten Threads
Thread thread[]=new Thread[10];
for (int i=0; i<10; i++){
thread[i]=new Thread(new PrintJob(printQueue),"Thread "+i);
}
// Starts the Threads
for (int i=0; i<10; i++){
thread[i].start();
}
}
}
執行結果:
Thread0: Going to print a job
Thread9: Going to print a job
Thread8: Going to print a job
Thread7: Going to print a job
Thread6: Going to print a job
Thread5: Going to print a job
Thread4: Going to print a job
Thread3: Going to print a job
Thread2: Going to print a job
Thread1: Going to print a job
Thread0: PrintQueuesTask: Printing a Job during 1 seconds
Thread0: The document has been printed
Thread9: PrintQueuesTask: Printing a Job during 3 seconds
Thread9: The document has been printed
Thread8: PrintQueuesTask: Printing a Job during 4 seconds
Thread7: PrintQueuesTask: Printing a Job during 3 seconds
Thread8: The document has been printed
Thread7: The document has been printed
Thread6: PrintQueuesTask: Printing a Job during 2 seconds
Thread6: The document has been printed
Thread5: PrintQueuesTask: Printing a Job during 4 seconds
Thread5: The document has been printed
Thread4: PrintQueuesTask: Printing a Job during 2 seconds
Thread3: PrintQueuesTask: Printing a Job during 3 seconds
Thread4: The document has been printed
Thread3: The document has been printed
Thread2: PrintQueuesTask: Printing a Job during 0 seconds
Thread2: The document has been printed
Thread1: PrintQueuesTask: Printing a Job during 3 seconds
Thread 1: The document has been printed