Java併發編程中級篇(二):使用Semaphore信號量進行多個資源併發控制

上一節中咱們使用了Semaphore信號量保護共享資源,可是它只能保護一個共享資源,當咱們須要同時保護多個共享資源的時候,咱們只須要在建立信號量的時候使用new Semaphore(int)構造方法,傳入參數是你想要保護的共享資源數目。java

/**
     * Creates a {@code Semaphore} with the given number of
     * permits and nonfair fairness setting.
     *
     * @param permits the initial number of permits available.
     *        This value may be negative, in which case releases
     *        must occur before any acquires will be granted.
     */
    public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }

仍是PrintQueue的例子,咱們把打印隊列中打印機數目增長到3臺,使用一個boolean[3]數組來標記打印機是否可用,同時使用3個信號量來保證這三個打印機的併發訪問控制。定義一個鎖來保證更改打印機狀態的時候的同步控制。獲取打印機資源的時候記錄打印機ID,並標記打印機處於使用狀態。釋放打印機資源的時候,把相應ID的打印機狀態置爲可用。數組

public class PrintQueue {
    private boolean freePrinters[];
    private Lock lockPrinters;
    private Semaphore semaphore;

    public PrintQueue() {
        this.freePrinters = new boolean[3];
        this.lockPrinters = new ReentrantLock();
        this.semaphore = new Semaphore(3);

        for (int i = 0; i < 3; i++) {
            this.freePrinters[i] = true;
        }
    }

    public void printJob(Object object) {
        try {
            semaphore.acquire();
            int assignedPrinter = getPrinter();

            long duration = (long)(Math.random() * 10);
            System.out.printf("%s: Print a Job in printer %d duration %d seconds.\n",
                    Thread.currentThread().getName(), assignedPrinter, duration);
            TimeUnit.SECONDS.sleep(duration);

            freePrinter(assignedPrinter);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release();
        }
    }

    private int getPrinter() {
        lockPrinters.lock();
        int printNo = -1;
        try {
            for (int i = 0; i < freePrinters.length; i++) {
                if (freePrinters[i]) {
                    printNo = i;
                    freePrinters[i] = false;
                    break;
                }
            }
        } finally {
            lockPrinters.unlock();
        }
        return printNo;
    }

    private void freePrinter(int printNo) {
        lockPrinters.lock();

        try {
            freePrinters[printNo] = true;
        } finally {
            lockPrinters.unlock();
        }
    }

打印Job線程類和主方法類不變併發

public class Job implements Runnable{
    private PrintQueue printQueue;

    public Job(PrintQueue printQueue) {
        this.printQueue = printQueue;
    }

    @Override
    public void run() {
        System.out.printf("%s: Going to print a Job.\n", Thread.currentThread().getName());
        printQueue.printJob(new Object());
        System.out.printf("%s: The Job has been printed.\n", Thread.currentThread().getName());
    }
}
public class Main {
    public static void main(String[] args) {
        PrintQueue printQueue = new PrintQueue();

        Thread[] threads = new Thread[10];
        for (int i = 1; i < 10; i++) {
            threads[i] = new Thread(new Job(printQueue));
        }

        for (int i = 1; i < 10; i++) {
            threads[i].start();
        }
    }
}

執行查看控制檯日誌,你能夠發現每次有三個打印Job能夠執行。dom

Thread-0: Going to print a Job.
Thread-8: Going to print a Job.
Thread-7: Going to print a Job.
Thread-6: Going to print a Job.
Thread-5: Going to print a Job.
Thread-4: Going to print a Job.
Thread-3: Going to print a Job.
Thread-2: Going to print a Job.
Thread-1: Going to print a Job.
Thread-8: Print a Job in printer 1 duration 2 seconds.
Thread-7: Print a Job in printer 2 duration 6 seconds.
Thread-0: Print a Job in printer 0 duration 2 seconds.
Thread-0: The Job has been printed.
Thread-5: Print a Job in printer 1 duration 7 seconds.
Thread-6: Print a Job in printer 0 duration 9 seconds.
Thread-8: The Job has been printed.
Thread-7: The Job has been printed.
Thread-4: Print a Job in printer 2 duration 1 seconds.
Thread-4: The Job has been printed.
Thread-3: Print a Job in printer 2 duration 6 seconds.
Thread-5: The Job has been printed.
Thread-2: Print a Job in printer 1 duration 7 seconds.
Thread-6: The Job has been printed.
Thread-1: Print a Job in printer 0 duration 2 seconds.
Thread-3: The Job has been printed.
Thread-1: The Job has been printed.
Thread-2: The Job has been printed.
相關文章
相關標籤/搜索