java 计数信号量和Semaphore类

时间:2022-10-04 15:10:23

使用场景:假设能够使用的资源个数有N个,而需要这些资源的线程个数又多余N个,这就会导致资源竞争,因此需要交通管制。这种情况下可以使用计数信号量。

java.util.concurrent包提供了表示信号量的Semaphore类。

资源的许可个数(permits)将通过Semaphore的构造函数来指定。

Semphore的acqyire方法用于确保存在可用资源。当存在可用资源时,线程会立即从acquire方法返回,同时信号量内部的资源个数减1。如无用资源,线程则阻塞在acquire方法内,直至出现可用资源。

Semphore的release方法用于释放资源。释放资源后,信号量内部的资源个数会增加1,。另外,如果acquire中存在等待的线程,那么其中一个线程会被唤醒,并从acquire方法返回。

例子:

提供资源的类:

public class BoundedResource {
	private final Semaphore semaphore;
	private final int permits;
	private final static Random random = new Random(314159);

	// 构造函数
	public BoundedResource(int permits) {
		this.semaphore = new Semaphore(permits);
		this.permits = permits;
	}

	// 使用资源
	public void use() throws InterruptedException {
		semaphore.acquire();
		try {
			doUser();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			semaphore.release();
		}
	}

	// 实际使用资源
	private void doUser() throws InterruptedException {
		Log.println("BEGIN:used=" + (permits - semaphore.availablePermits()));
		Thread.sleep(random.nextInt(500));
		Log.println("END:used=" + (permits - semaphore.availablePermits()));
	}

}

user线程类:

public class UserThread extends Thread {

	private final static Random random = new Random(25635);
	private final BoundedResource resource;

	public UserThread(BoundedResource resource) {
		this.resource = resource;
	}

	@Override
	public void run() {
		try {
			for (;;) {
				resource.use();
				Thread.sleep(random.nextInt(3000));
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}

main类:

public class Main {

	public static void main(String[] args) {
		// 设置3个资源
		BoundedResource resource = new BoundedResource(3);
		// 10个线程使用资源
		for (int i = 0; i < 10; i++) {
			new UserThread(resource).start();
		}
	}

}