信号灯是一个控制对一个或多个共享资源的访问的计数器。 当一个线程想访问共享资源之一时:
数据类 : PrintQueue
private Semaphore semaphore; public PrintQueue() { semaphore = new Semaphore(1); }
public void printJob(Object document) { try { semaphore.acquire(); long duration=(long)(Math.random()*10); System.out.printf("%s: PrintQueue: Printing a Job during %d seconds\n", Thread.currentThread().getName(),duration); Thread.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); } }
线程类 : Job
private PrintQueue printQueue; public Job(PrintQueue printQueue) { this.printQueue = printQueue; }
System.out.printf("%s: Going to print a job\n",Thread.currentThread().getName()); printQueue.printJob(new Object()); System.out.printf("%s: The document has been printed\n",Thread.currentThread().getName());
控制类 : Main
PrintQueue printQueue = new PrintQueue(); Thread[] threads = new Thread[10]; for (int i=0; i<10; i++) { threads[i] = new Thread(new Job(printQueue), "Thread" + i); } for (int i=0; i<10; i++) { threads[i].start(); }
本例的关键在于 PrintQueue 类的 printJob 方法。此方法展示了使用信号灯来实现临界区并保护对一个共享资源的保护时,必须要做的:
另一个重点在于 PrintQueue 类的构造函数内对 Semaphore 对象的初始化。 给 Semaphore 的构造函数传参 1 ,创建了一个二元信号灯。内部计数器的初识值为 1,这样可以保护对一个共享资源(在本例中是打印队列)的访问。
当启动了 10 个线程,第 1 个获得了信号能访问临界区。其他的被信号灯阻塞直到获得信号的线程释放信号。 当信号被释放,信号灯选择等待线程中的一个赋予它访问临界区的权限。 所有线程都会打印它们的文件,但是是一个接一个的。