Java并发编程中Semaphore的用法

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

你可能感兴趣的:(Java,Multi-Thread)