高级同步器:信号量Semaphore

时间:2021-08-03 15:21:04

引自:https://blog.csdn.net/Dason_yu/article/details/79734425

一、信号量
一个计数信号量。从概念上讲,信号量维护了一个许可集。Semaphore经常用于限制获取某种资源的线程数量。在java并发中,即Semaphore维护指定数量许可,当Semaphore中有额外(空闲)的许可时,线程获取到许可信号后(调用acquire()),线程才允许被执行,否则将被阻塞。当线程执行完毕,就会将占用的许可释放(调用release())。

此类的构造方法可选地接受一个公平 参数。当设置为 false 时,此类不对线程获取许可的顺序做任何保证。当公平设置为 true 时,信号量保证对于任何调用获取方法的线程而言,都按照处理它们调用这些方法的顺序(即先进先出;FIFO)来选择线程、获得许可。注意,FIFO 排序必然应用到这些方法内的指定内部执行点。所以,可能某个线程先于另一个线程调用了 acquire,但是却在该线程之后到达排序点,并且从方法返回时也类似。

二、用法

package com.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * 信号量一般用于用于限制获取某种资源的线程数量
 * 
 * @author Dason
 *
 */
public class SemaphoreTest {
    
    public static void main(String[] args) {
        ExecutorService service = Executors.newCachedThreadPool();
        // 创建一个管理 3 个许可的信号量
        final Semaphore sp = new Semaphore(3);
        for (int i = 0; i < 10; i++) {
            Runnable runnable = new Runnable() {
                public void run() {
                    try {
                        // 获取一个许可,若没有则被阻塞
                        sp.acquire();
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                    // availablePermits(): 返回此信号量中当前可用的许可数.
                    System.out.println(
                            "线程" + Thread.currentThread().getName() + "进入,当前已有" + (3 - sp.availablePermits()) + "个并发");
                    try {
                        Thread.sleep((long) (Math.random() * 100));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("线程" + Thread.currentThread().getName() + "即将离开");
                    // 释放一个许可.
                    sp.release();
                    // 下面代码有时候执行不准确,因为其没有和上面的代码合成原子单元
                    System.out.println(
                            "线程" + Thread.currentThread().getName() + "已离开,当前已有" + (3 - sp.availablePermits()) + "个并发");
                }
            };
            service.execute(runnable);
        }
    }

}