Semaphore又称信号量,是操作系统中的一个概念,在Java并发编程中,信号量控制的是线程并发的数量。

    public Semaphore(int permits)

    其中参数permits就是允许同时运行的线程数目;

    下面先看一个信号量实现单线程的例子,也就是permits=1:

    1. package concurrent.semaphore;
    2. import java.util.concurrent.Semaphore;
    3. public class Driver {
    4. // 控制线程的数目为1,也就是单线程
    5. private Semaphore semaphore = new Semaphore(1);
    6. public void driveCar() {
    7. try {
    8. // 从信号量中获取一个允许机会
    9. semaphore.acquire();
    10. System.out.println(Thread.currentThread().getName() + " start at " + System.currentTimeMillis());
    11. Thread.sleep(1000);
    12. System.out.println(Thread.currentThread().getName() + " stop at " + System.currentTimeMillis());
    13. // 释放允许,将占有的信号量归还
    14. semaphore.release();
    15. } catch (InterruptedException e) {
    16. e.printStackTrace();
    17. }
    18. }
    19. }
    1. package concurrent.semaphore;
    2. public class Car extends Thread{
    3. private Driver driver;
    4. public Car(Driver driver) {
    5. super();
    6. this.driver = driver;
    7. }
    8. public void run() {
    9. driver.driveCar();
    10. }
    11. }
    1. public class Run {
    2. public static void main(String[] args) {
    3. Driver driver = new Driver();
    4. for (int i = 0; i < 5; i++) {
    5. (new Car(driver)).start();
    6. }
    7. }
    8. }
    1. Thread-0 start at 1482664517179
    2. Thread-0 stop at 1482664518179
    3. Thread-3 start at 1482664518179
    4. Thread-3 stop at 1482664519179
    5. Thread-1 start at 1482664519179
    6. Thread-1 stop at 1482664520179
    7. Thread-4 start at 1482664520179
    8. Thread-4 stop at 1482664521180
    9. Thread-2 start at 1482664521180
    10. Thread-2 stop at 1482664522180

    从输出可以看出,改输出与单线程是一样的,执行完一个线程,再执行另一个线程。

    如果信号量大于1呢,我们将信号量设为3:

    1. public class Driver {
    2. // 将信号量设为3
    3. private Semaphore semaphore = new Semaphore(3);
    4. public void driveCar() {
    5. try {
    6. semaphore.acquire();
    7. System.out.println(Thread.currentThread().getName() + " start at " + System.currentTimeMillis());
    8. Thread.sleep(1000);
    9. System.out.println(Thread.currentThread().getName() + " stop at " + System.currentTimeMillis());
    10. semaphore.release();
    11. } catch (InterruptedException e) {
    12. e.printStackTrace();
    13. }
    14. }
    15. }
    1. Thread-0 start at 1482665412515
    2. Thread-3 start at 1482665412517
    3. Thread-1 start at 1482665412517
    4. Thread-3 stop at 1482665413517
    5. Thread-0 stop at 1482665413517
    6. Thread-4 start at 1482665413517
    7. Thread-2 start at 1482665413517
    8. Thread-1 stop at 1482665413518
    9. Thread-4 stop at 1482665414517
    10. Thread-2 stop at 1482665414517

    从输出的前三行可以看出,有3个线程可以同时执行,三个线程同时运行的时候,第四个线程必须等待前面有一个要完成,才能执行第四个线程启动。

    当然也可以用acquire动态地添加permits的数量,它表示的是一次性获取许可的数量,比如:

    1. public class Driver {
    2. // 信号量共10个
    3. private Semaphore semaphore = new Semaphore(10);
    4. public void driveCar() {
    5. try {
    6. // 每次获取3个
    7. semaphore.acquire(3);
    8. System.out.println(Thread.currentThread().getName() + " start at " + System.currentTimeMillis());
    9. Thread.sleep(1000);
    10. System.out.println(Thread.currentThread().getName() + " stop at " + System.currentTimeMillis());
    11. semaphore.release();
    12. } catch (InterruptedException e) {
    13. e.printStackTrace();
    14. }
    15. }
    16. }

    在上述代码中总的信号量除以每次获取的许可数即10/3=3,就是说可以允许3个线程一起运行。

    我们可以用public int availablePermits()查看现在可用的信号量:

    1. public class SemaphoreAvaliablePermits {
    2. public static void main(String[] args) {
    3. try{
    4. Semaphore semaphore = new Semaphore(10);
    5. System.out.println("Semaphore available permits: " + semaphore.availablePermits());
    6. semaphore.acquire();
    7. System.out.println("Semaphore available permits: " + semaphore.availablePermits());
    8. semaphore.acquire(2);
    9. System.out.println("Semaphore available permits: " + semaphore.availablePermits());
    10. semaphore.acquire(3);
    11. System.out.println("Semaphore available permits: " + semaphore.availablePermits());
    12. semaphore.acquire(4);
    13. System.out.println("Semaphore available permits: " + semaphore.availablePermits());
    14. semaphore.release();
    15. System.out.println("Semaphore available permits: " + semaphore.availablePermits());
    16. semaphore.release(2);
    17. System.out.println("Semaphore available permits: " + semaphore.availablePermits());
    18. semaphore.release(3);
    19. System.out.println("Semaphore available permits: " + semaphore.availablePermits());
    20. semaphore.release(4);
    21. System.out.println("Semaphore available permits: " + semaphore.availablePermits());
    22. }catch (InterruptedException e){
    23. e.printStackTrace();
    24. }
    25. }
    26. }
    1. Semaphore available permits: 10
    2. Semaphore available permits: 9
    3. Semaphore available permits: 7
    4. Semaphore available permits: 4
    5. Semaphore available permits: 0
    6. Semaphore available permits: 1
    7. Semaphore available permits: 3
    8. Semaphore available permits: 6
    9. Semaphore available permits: 10

    还有一个方法public int drainPermits(),这个方法返回即可所有的许可数目,并将许可置0:

    1. public class SemaphoreDrainPermits {
    2. public static void main(String[] args) {
    3. try{
    4. Semaphore semaphore = new Semaphore(10);
    5. System.out.println("Semaphore available permits: " + semaphore.availablePermits());
    6. semaphore.acquire();
    7. System.out.println("Semaphore available permits: " + semaphore.availablePermits());
    8. System.out.println("Semaphore drain permits" + semaphore.drainPermits());
    9. System.out.println("Semaphore available permits: " + semaphore.availablePermits());
    10. System.out.println("Semaphore drain permits" + semaphore.drainPermits());
    11. System.out.println("Semaphore available permits: " + semaphore.availablePermits());
    12. }catch (InterruptedException e){
    13. e.printStackTrace();
    14. }
    15. }
    16. }
    1. Semaphore available permits: 10
    2. Semaphore available permits: 9
    3. Semaphore drain permits9
    4. Semaphore available permits: 0
    5. Semaphore drain permits0
    6. Semaphore available permits: 0