声明:本文是《 Java 7 Concurrency Cookbook 》的第三章, 作者: Javier Fernández González 译者:郑玉婷
控制并发访问多个资源
在并发访问资源的控制中,你学习了信号量(semaphores)的基本知识。
在上个指南,你实现了使用binary semaphores的例子。那种semaphores是用来保护访问一个共享资源的,或者说一个代码片段每次只能被一个线程执行。但是semaphores也可以用来保护多个资源的副本,也就是说当你有一个代码片段每次可以被多个线程执行。
在这个指南中,你将学习怎样使用semaphore来保护多个资源副本。你将实现的例子会有一个print queue但可以在3个不同的打印机上打印文件。
准备
指南中的例子是使用 Eclipse IDE 来实现的。如果你使用Eclipse 或者其他的IDE,例如NetBeans, 打开并创建一个新的java任务。实现在控制并发访问资源里描述的例子。
怎么做呢…
按照这些步骤来实现下面的例子:
02 |
private boolean freePrinters[];
|
05 |
private Lock lockPrinters;
|
10 |
semaphore= new Semaphore( 3 );
|
11 |
freePrinters= new boolean [ 3 ];
|
13 |
for ( int i= 0 ; i< 3 ; i++){
|
16 |
lockPrinters= new ReentrantLock();
|
20 |
public void printJob (Object document){
|
27 |
int assignedPrinter=getPrinter();
|
30 |
long duration=( long )(Math.random()* 10 );
|
31 |
System.out.printf( "%s: PrintQueue: Printing a Job in Printer%d during %d seconds\n" ,Thread.currentThread().getName(), assignedPrinter,duration);
|
32 |
TimeUnit.SECONDS.sleep(duration); |
35 |
freePrinters[assignedPrinter]= true ;
|
36 |
} catch (InterruptedException e) {
|
43 |
private int getPrinter() {
|
53 |
for ( int i= 0 ; i<freePrinters.length; i++) {
|
56 |
freePrinters[i]= false ;
|
62 |
} catch (Exception e) {
|
65 |
lockPrinters.unlock();
|
它是怎么工作的…
在例子中的PrintQueue类的关键是:Semaphore对象创建的构造方法是使用3作为参数的。这个例子中,前3个调用acquire() 方法的线程会获得临界区的访问权,其余的都会被阻塞 。当一个线程结束临界区的访问并解放semaphore时,另外的线程才可能获得访问权。
在这个临界区,线程获得被分配打印的打印机的引索值。例子的这部分让例子更真实,而且它没有使用任何与semaphores相关的代码。以下的裁图展示了这个例子的执行输出:
每个文档都被安排到第一个空闲的打印机打印。
更多…
The acquire(), acquireUninterruptibly(), tryAcquire(),和release()方法有一个外加的包含一个int参数的版本。这个参数表示 线程想要获取或者释放semaphore的许可数。也可以这样说,这个线程想要删除或者添加到semaphore的内部计数器的单位数量。在这个例子中acquire(), acquireUninterruptibly(), 和tryAcquire() 方法, 如果计数器的值小于许可值,那么线程就会被阻塞直到计数器到达或者大于许可值。
参见
第三章,线程同步应用:并发地访问资源的控制
第八章,同步应用的测试:修改Lock接口
第二章,基本线程同步:修改lock的公平性
文章转自 并发编程网-ifeve.com