Semaphore

Semaphore: 计数信号量,它的本质是一个”共享锁”,可以用来控制并发数。通过协调哥哥线程,以保证合理的使用公共资源。

首先Semaphore的构造参数接受一个整形数字,表示的就是允许多少个线程获得许可证,首先通过acquire()获得许可证,当线程数达到构造出来的数字时,其他线程会阻塞,直到有其他运行的线程通过release()方法归还许可证。也可以通过tryAcquire()方法尝试获取许可证。

Semaphore的其他一些方法

// 创建给定数量的许可证,且可设置是否是公平的信号量
Semaphore(int permits, boolean fair)

// 信号量获取一个许可,若没有可用的许可证会一直阻塞。
void acquire()

// 返回此信号量中当前可用的许可数。
int availablePermits()

// 获取并返回立即可用的所有许可。
int drainPermits()

// 返回正在等待获取的线程。
protected Collection<Thread> getQueuedThreads()

// 返回正在等待获取的线程数目。
int getQueueLength()

// 查询是否有线程正在等待获取。
boolean hasQueuedThreads()

// 判断信号量的是否公平,公平则返回true。
boolean isFair()

// 减小reduction个可用许可的数目。
protected void reducePermits(int reduction)

// 释放一个许可。
void release()

// 释放给定数目的许可。
void release(int permits)

// 仅在调用时此信号量存在一个可用许可,才从信号量获取许可。
boolean tryAcquire()

// 仅在调用时此信号量中有给定数目的许可时,才从此信号量中获取这些许可。
boolean tryAcquire(int permits)

一个例子理解Semaphore

import java.util.concurrent.*;

/**
 * @author fitz.bai
 */
public class MyThread16 {
    private static Semaphore semaphore;
    private static int SIZE = 5;

    public static void main(String[] args) {
        semaphore = new Semaphore(SIZE);
        Runnable runnable = () -> {
            try {
                semaphore.acquire();
                System.out.println(Thread.currentThread().getName() + "获得信号量,时间为" + System.currentTimeMillis());
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println(Thread.currentThread().getName() + "释放信号量,时间为" + System.currentTimeMillis());
                semaphore.release();
            }
        };
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(20000));
        for (int i = 0; i < 10; i++) {
            threadPoolExecutor.execute(runnable);
        }
        threadPoolExecutor.shutdown();

    }
}
// 运行结果
pool-1-thread-5获得信号量,时间为1533642550282
pool-1-thread-4获得信号量,时间为1533642550282
pool-1-thread-1获得信号量,时间为1533642550281
pool-1-thread-3获得信号量,时间为1533642550282
pool-1-thread-2获得信号量,时间为1533642550281
pool-1-thread-3释放信号量,时间为1533642551355
pool-1-thread-4释放信号量,时间为1533642551355
pool-1-thread-1释放信号量,时间为1533642551355
pool-1-thread-5释放信号量,时间为1533642551355
pool-1-thread-7获得信号量,时间为1533642551356
pool-1-thread-9获得信号量,时间为1533642551356
pool-1-thread-8获得信号量,时间为1533642551356
pool-1-thread-6获得信号量,时间为1533642551356
pool-1-thread-2释放信号量,时间为1533642551359
pool-1-thread-10获得信号量,时间为1533642551359
pool-1-thread-7释放信号量,时间为1533642552360
pool-1-thread-10释放信号量,时间为1533642552360
pool-1-thread-8释放信号量,时间为1533642552360
pool-1-thread-6释放信号量,时间为1533642552360
pool-1-thread-9释放信号量,时间为1533642552360
结论:

从例子和结果中明显看出,刚开始有5个线程获得了信号量,达到设置的数量,然后又有4个线程几乎同时释放了信号量,然后相当于有了4个坑,那么紧接着又有4个线程获得信号量。自始至终,都是同时直邮5个。