Java并发编程之线程治理(高级线程同步8)

Java并发编程之线程管理(高级线程同步8)

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)而已。可以同时让三个线程一起执行,这样的话,程序的效率明显提高了。