3.2 控制并发地访问一个资源的多个备份
在这一节中,我将实现一个二进制信号。这些类型的信号能够被用来保护对于一个共享资源的访问,或者是对于同一时刻只能够被一个线程执行的临界部分。当你需要保护一个资源的不同类型的备份时,或者是在同一时刻只能让一个线程执行,信号都可以用来现实这样的功能。
请看下面的例子,这个例子已经在上一节中已经讲过,这里只要做稍微的修改就可以了。
定义PrintQueueTask类:
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
importjava.util.concurrent.locks.ReentrantLock;
/**
* 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;
/**
* Array to control what printer is free
*/
private booleanfreePrinters[];
/**
* Lock to control the access to thefreePrinters array
*/
private Lock lockPrinters;
/**
* Constructor of the class. Initializes thesemaphore
*/
public PrintQueueTask(){
semaphore=new Semaphore(3);
freePrinters = new boolean[3];
for(int k = 0; k < 3; k++){
freePrinters[k] = true;
}
lockPrinters = new ReentrantLock();
}
/**
* 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();
// Get the number of the free printer
int assignedPrinter = getPrinter();
Long duration=(long)10;
System.out.printf("%s: PrintQueuesTask: Printing a Job during %d seconds\n",Thread.currentThread().getName(),duration);
Thread.sleep(duration);
TimeUnit.SECONDS.sleep(duration);
// Free the printer
freePrinters[assignedPrinter] = true;
} 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();
}
}
private intgetPrinter() {
int ret=-1;
try {
// Get the access to the array
lockPrinters.lock();
// Look for the first free printer
for (int i=0; i<freePrinters.length; i++) {
if (freePrinters[i]){
ret=i;
freePrinters[i]=false;
break;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// Free the access to the array
lockPrinters.unlock();
}
return ret;
}
}
定义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 voidrun() { 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 staticvoidmain (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(); } } }
执行结果:
Thread1: Going to print a job
Thread9: Going to print a job
Thread8: Going to print a job
Thread4: Going to print a job
Thread7: Going to print a job
Thread5: Going to print a job
Thread6: Going to print a job
Thread3: Going to print a job
Thread0: Going to print a job
Thread2: Going to print a job
Thread9: PrintQueuesTask: Printing a Job during 10 seconds
Thread8: PrintQueuesTask: Printing a Job during 10 seconds
Thread1: PrintQueuesTask: Printing a Job during 10 seconds
Thread1: The document has been printed
Thread9: The document has been printed
Thread8: The document has been printed
Thread4: PrintQueuesTask: Printing a Job during 10 seconds
Thread5: PrintQueuesTask: Printing a Job during 10 seconds
Thread7: PrintQueuesTask: Printing a Job during 10 seconds
Thread4: The document has been printed
Thread5: The document has been printed
Thread3: PrintQueuesTask: Printing a Job during 10 seconds
Thread6: PrintQueuesTask: Printing a Job during 10 seconds
Thread7: The document has been printed
Thread0: PrintQueuesTask: Printing a Job during 10 seconds
Thread6: The document has been printed
Thread2: PrintQueuesTask: Printing a Job during 10 seconds
Thread3: The document has been printed
Thread0: The document has been printed
Thread2: The document has been printed
从这个程序中,我们发现,它比单个的访问一个资源多了几个信号(Semaphores)而已。可以同时让三个线程一起执行,这样的话,程序的效率明显提高了。