Semaphore又称信号量,是操作系统中的一个概念,在Java并发编程中,信号量控制的是线程并发的数量。
public Semaphore(int permits)
其中参数permits就是允许同时运行的线程数目;
下面先看一个信号量实现单线程的例子,也就是permits=1:
package concurrent.semaphore;import java.util.concurrent.Semaphore;public class Driver {// 控制线程的数目为1,也就是单线程private Semaphore semaphore = new Semaphore(1);public void driveCar() {try {// 从信号量中获取一个允许机会semaphore.acquire();System.out.println(Thread.currentThread().getName() + " start at " + System.currentTimeMillis());Thread.sleep(1000);System.out.println(Thread.currentThread().getName() + " stop at " + System.currentTimeMillis());// 释放允许,将占有的信号量归还semaphore.release();} catch (InterruptedException e) {e.printStackTrace();}}}
package concurrent.semaphore;public class Car extends Thread{private Driver driver;public Car(Driver driver) {super();this.driver = driver;}public void run() {driver.driveCar();}}
public class Run {public static void main(String[] args) {Driver driver = new Driver();for (int i = 0; i < 5; i++) {(new Car(driver)).start();}}}
Thread-0 start at 1482664517179Thread-0 stop at 1482664518179Thread-3 start at 1482664518179Thread-3 stop at 1482664519179Thread-1 start at 1482664519179Thread-1 stop at 1482664520179Thread-4 start at 1482664520179Thread-4 stop at 1482664521180Thread-2 start at 1482664521180Thread-2 stop at 1482664522180
从输出可以看出,改输出与单线程是一样的,执行完一个线程,再执行另一个线程。
如果信号量大于1呢,我们将信号量设为3:
public class Driver {// 将信号量设为3private Semaphore semaphore = new Semaphore(3);public void driveCar() {try {semaphore.acquire();System.out.println(Thread.currentThread().getName() + " start at " + System.currentTimeMillis());Thread.sleep(1000);System.out.println(Thread.currentThread().getName() + " stop at " + System.currentTimeMillis());semaphore.release();} catch (InterruptedException e) {e.printStackTrace();}}}
Thread-0 start at 1482665412515Thread-3 start at 1482665412517Thread-1 start at 1482665412517Thread-3 stop at 1482665413517Thread-0 stop at 1482665413517Thread-4 start at 1482665413517Thread-2 start at 1482665413517Thread-1 stop at 1482665413518Thread-4 stop at 1482665414517Thread-2 stop at 1482665414517
从输出的前三行可以看出,有3个线程可以同时执行,三个线程同时运行的时候,第四个线程必须等待前面有一个要完成,才能执行第四个线程启动。
当然也可以用acquire动态地添加permits的数量,它表示的是一次性获取许可的数量,比如:
public class Driver {// 信号量共10个private Semaphore semaphore = new Semaphore(10);public void driveCar() {try {// 每次获取3个semaphore.acquire(3);System.out.println(Thread.currentThread().getName() + " start at " + System.currentTimeMillis());Thread.sleep(1000);System.out.println(Thread.currentThread().getName() + " stop at " + System.currentTimeMillis());semaphore.release();} catch (InterruptedException e) {e.printStackTrace();}}}
在上述代码中总的信号量除以每次获取的许可数即10/3=3,就是说可以允许3个线程一起运行。
我们可以用public int availablePermits()查看现在可用的信号量:
public class SemaphoreAvaliablePermits {public static void main(String[] args) {try{Semaphore semaphore = new Semaphore(10);System.out.println("Semaphore available permits: " + semaphore.availablePermits());semaphore.acquire();System.out.println("Semaphore available permits: " + semaphore.availablePermits());semaphore.acquire(2);System.out.println("Semaphore available permits: " + semaphore.availablePermits());semaphore.acquire(3);System.out.println("Semaphore available permits: " + semaphore.availablePermits());semaphore.acquire(4);System.out.println("Semaphore available permits: " + semaphore.availablePermits());semaphore.release();System.out.println("Semaphore available permits: " + semaphore.availablePermits());semaphore.release(2);System.out.println("Semaphore available permits: " + semaphore.availablePermits());semaphore.release(3);System.out.println("Semaphore available permits: " + semaphore.availablePermits());semaphore.release(4);System.out.println("Semaphore available permits: " + semaphore.availablePermits());}catch (InterruptedException e){e.printStackTrace();}}}
Semaphore available permits: 10Semaphore available permits: 9Semaphore available permits: 7Semaphore available permits: 4Semaphore available permits: 0Semaphore available permits: 1Semaphore available permits: 3Semaphore available permits: 6Semaphore available permits: 10
还有一个方法public int drainPermits(),这个方法返回即可所有的许可数目,并将许可置0:
public class SemaphoreDrainPermits {public static void main(String[] args) {try{Semaphore semaphore = new Semaphore(10);System.out.println("Semaphore available permits: " + semaphore.availablePermits());semaphore.acquire();System.out.println("Semaphore available permits: " + semaphore.availablePermits());System.out.println("Semaphore drain permits" + semaphore.drainPermits());System.out.println("Semaphore available permits: " + semaphore.availablePermits());System.out.println("Semaphore drain permits" + semaphore.drainPermits());System.out.println("Semaphore available permits: " + semaphore.availablePermits());}catch (InterruptedException e){e.printStackTrace();}}}
Semaphore available permits: 10Semaphore available permits: 9Semaphore drain permits9Semaphore available permits: 0Semaphore drain permits0Semaphore available permits: 0
