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 1482664517179
Thread-0 stop at 1482664518179
Thread-3 start at 1482664518179
Thread-3 stop at 1482664519179
Thread-1 start at 1482664519179
Thread-1 stop at 1482664520179
Thread-4 start at 1482664520179
Thread-4 stop at 1482664521180
Thread-2 start at 1482664521180
Thread-2 stop at 1482664522180
从输出可以看出,改输出与单线程是一样的,执行完一个线程,再执行另一个线程。
如果信号量大于1呢,我们将信号量设为3:
public class Driver {
// 将信号量设为3
private 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 1482665412515
Thread-3 start at 1482665412517
Thread-1 start at 1482665412517
Thread-3 stop at 1482665413517
Thread-0 stop at 1482665413517
Thread-4 start at 1482665413517
Thread-2 start at 1482665413517
Thread-1 stop at 1482665413518
Thread-4 stop at 1482665414517
Thread-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: 10
Semaphore available permits: 9
Semaphore available permits: 7
Semaphore available permits: 4
Semaphore available permits: 0
Semaphore available permits: 1
Semaphore available permits: 3
Semaphore available permits: 6
Semaphore 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: 10
Semaphore available permits: 9
Semaphore drain permits9
Semaphore available permits: 0
Semaphore drain permits0
Semaphore available permits: 0