信号量是一个计数器,保护对一个或多个共享资源的访问。
1965年Edsgar Dijkstra引入信号量概念,并在THEOS操作系统中第一次使用。
当线程想要使用共享资源时,它必须获得一个信号量。如果信号量的内部计数器大于0,信号量递减计数器值并允许访问共享资源。如果信号量计数器等于0,则阻塞线程,直到计数器大于0。当线程使用完共享资源时,则必须释放信号量,递增信号量的内部计数器值。
信号量在Java的Semaphore类中实现。
本节将学习关于信号量的状态信息,以及如何获取这些信息。
准备工作
本范例通过Eclipse开发工具实现。如果使用诸如NetBeans的开发工具,打开并创建一个新的Java项目。
实现过程
通过如下步骤实现范例:
-
创建名为Task的类,实现Runnable接口:
public class Task implements Runnable {
-
声明名为semaphore的私有Semaphore属性:
private final Semaphore semaphore;
-
实现类构造函数,初始化属性:
public Task(Semaphore semaphore){ this.semaphore=semaphore; }
-
实现run()方法,首先获取信号量属性的许可并输出指明这种情况的信息到控制台:
@Override public void run() { try { semaphore.acquire(); System.out.printf("%s: Get the semaphore.\n", Thread.currentThread().getName());
-
然后使用sleep()方法设置线程休眠两秒钟,最后释放许可并输出指明这种情况的信息到控制台:
TimeUnit.SECONDS.sleep(2); System.out.println(Thread.currentThread().getName()+": Release the semaphore."); } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); } } }
-
实现本范例主类,创建名为Main的类,包含main()方法:
public class Main { public static void main(String[] args) throws Exception{
-
创建名为semaphore的Semaphore对象,包含三个许可:
Semaphore semaphore=new Semaphore(3);
-
创建数组存储10个Thread对象:
Thread threads[]=new Thread[10];
-
创建和启动10个Thread对象执行10个Task对象。启动线程之后,设置线程休眠200毫秒,调用showLog()方法输出Semaphore类的信息到控制台:
for (int i=0; i<threads.length; i++) { Task task=new Task(semaphore); threads[i]=new Thread(task); threads[i].start(); TimeUnit.MILLISECONDS.sleep(200); showLog(semaphore); }
-
创建重复五次操作的循环,每次操作调用showLog()方法输出semaphore的信息到控制台,并设置线程休眠1秒钟:
for (int i=0; i<5; i++) { showLog(semaphore); TimeUnit.SECONDS.sleep(1); } }
-
实现showLog()方法,将Semaphore对象作为参数接收。输出关于semaphore的可用许可、排队线程和许可的信息到控制台:
private static void showLog(Semaphore semaphore) { System.out.printf("********************\n"); System.out.printf("Main: Semaphore Log\n"); System.out.printf("Main: Semaphore: Avalaible Permits: %d\n", semaphore.availablePermits()); System.out.printf("Main: Semaphore: Queued Threads: %s\n", semaphore.hasQueuedThreads()); System.out.printf("Main: Semaphore: Queue Length: %d\n", semaphore.getQueueLength()); System.out.printf("Main: Semaphore: Fairness: %s\n", semaphore.isFair()); System.out.printf("********************\n"); } }
扩展学习
本节使用到如下方法获得semaphore的信息:
- availablePermits():返回int值,是信号量可用资源的数量。
- hasQueuedThreads():返回Boolean值,指明是否有线程等待由信号量保护的资源。
- getQueueLength():返回等待由信号量保护的资源的线程数。
- isFair():返回Boolean值,指明信号量是否激活了公平模式。当公平模式已激活(返回true值),锁需要选择其它线程并允许访问共享资源,它选择最长等待线程。如果公平模式未激活(返回false值),则无法保证选择哪个线程来获得对共享资源的访问。
更多关注
- 第三章“线程同步功能”中的“控制并发访问资源副本”小节