Semaphore又称信号量。在Java并发编程中,信号量控制的是线程并发的数量。
public Semaphore(int permits)
其中参数permits就是允许同时运行的线程数目;
下面先看一个信号量实现单线程的例子,也就是permits=1:
package queue;
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 queue;
public class Car extends Thread{
private Driver driver;
public Car(Driver driver) {
super();
this.driver = driver;
}
public void run() {
driver.driveCar();
}
}
package queue;
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 1534040621478
Thread-0 stop at 1534040622481
Thread-1 start at 1534040622481
Thread-1 stop at 1534040623481
Thread-2 start at 1534040623481
Thread-2 stop at 1534040624481
Thread-3 start at 1534040624482
Thread-3 stop at 1534040625482
Thread-4 start at 1534040625482
Thread-4 stop at 1534040626483
执行完一个线程,再执行另一个线程。
如果信号量大于1呢,我们将信号量设为3:
输出:
Thread-1 start at 1534041046941
Thread-2 start at 1534041046942
Thread-0 start at 1534041046941
Thread-1 stop at 1534041047942
Thread-3 start at 1534041047943
Thread-2 stop at 1534041047943
Thread-4 start at 1534041047944
Thread-0 stop at 1534041047944
Thread-4 stop at 1534041048944
Thread-3 stop at 1534041048945
从输出的前三行可以看出,有3个线程可以同时执行,三个线程同时运行的时候,第四个线程必须等待前面有一个要完成,才能执行第四个线程启动。
当然也可以用acquire动态地添加permits的数量,它表示的是一次性获取许可的数量,比如:
package queue;
import java.util.concurrent.Semaphore;
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()
查看现在可用的信号量:
package queue;
import java.util.concurrent.Semaphore;
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:
package queue;
import java.util.concurrent.Semaphore;
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
综合应用
package queue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.SynchronousQueue;
public class Test {
public static void main(String[] args) {
final Semaphore semaphore = new Semaphore(1);
final SynchronousQueue<String> queue = new SynchronousQueue<String>();
for(int i=0;i<10;i++){
new Thread(new Runnable(){
@Override
public void run() {
try {
semaphore.acquire();
String input = queue.take();
String output = TestDo.doSome(input);
System.out.println(Thread.currentThread().getName()+ ":" + output);
semaphore.release();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
System.out.println("begin:"+(System.currentTimeMillis()/1000));
for(int i=0;i<10;i++){ //这行不能改动
String input = i+""; //这行不能改动
try {
queue.put(input);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
//不能改动此TestDo类
class TestDo {
public static String doSome(String input){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String output = input + ":"+ (System.currentTimeMillis() / 1000);
return output;
}
}