使用场景:假设能够使用的资源个数有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(); } } }