您的位置:首页 > 编程语言 > Java开发

Java并发编程中级篇(二):使用Semaphore信号量进行多个资源并发控制

2016-11-25 00:00 549 查看
上一节中我们使用了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;
}

@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可以执行。

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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐