上一節中咱們使用了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.