独角兽企业重金招聘Python工程师标准>>>
上一节中我们使用了Semaphore信号量保护共享资源,但是它只能保护一个共享资源,当我们需要同时保护多个共享资源的时候,我们只需要在创建信号量的时候使用new Semaphore(int)构造方法,传入参数是你想要保护的共享资源数目。
/*** 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;}@Overridepublic 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可以执行。
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.