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