Java并发编程Semaphore

时间:2023-02-04 20:48:26

信号量

信号量类Semaphore,用来保护对唯一共享资源的访问。一个简单的打印队列,并发任务进行打印,加入信号量同时之能有一个线程进行打印任务 。

import java.util.concurrent.Semaphore;

public class PrintQueue {
public PrintQueue() {

semaphore = new Semaphore(1,true);
}

private final Semaphore semaphore;

public void printJob(Object document) {
try {
semaphore.acquire();

long duration = (long) (Math.random() * 10);

System.out.println("执行打印"+Thread.currentThread().getName() + "花费时间"+ duration+ "秒");
Thread.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
semaphore.release();
}
}
}


public class Job implements Runnable{

private PrintQueue printQueue;

public Job(PrintQueue printQueue){

this.printQueue=printQueue;
}
@Override
public void run() {
printQueue.printJob(new Object());
System.out.println("文档被打印"+Thread.currentThread().getName());
}
}

public class Main {
public static void main(String[] args) {
PrintQueue p = new PrintQueue();
Thread thread[] = new Thread[10];
for (int i = 0; i <thread.length; i++) {
thread[i]=new Thread(new Job(p),"Thread"+i);
}
for (int i = 0; i < thread.length; i++) {
thread[i].start();
}
}
}
----------------------输出结果 ---------------------------
执行打印Thread0花费时间9
文档被打印Thread0
执行打印Thread3花费时间9
文档被打印Thread3
执行打印Thread2花费时间6
文档被打印Thread2
执行打印Thread1花费时间4
文档被打印Thread1
执行打印Thread5花费时间6
文档被打印Thread5
执行打印Thread7花费时间3
文档被打印Thread7
执行打印Thread9花费时间8
文档被打印Thread9
执行打印Thread8花费时间0
文档被打印Thread8
执行打印Thread6花费时间8
文档被打印Thread6
执行打印Thread4花费时间7
文档被打印Thread4
如上声明一个打印队列,构造器初始化信号量对象来保护对打印队列的访问。semaphore.acquire();获取信号量,最后semaphore.release();用来释放。启动10个线程进行打印的操作,第一个获得信号量的线程将能访问临界区,其余的线程将被信号量阻塞,直到信号量的释放。信号量被释放后,将选择一个正在等待的线程并且允许它访问临界区。

简单代码分析


根据boolean fair ,来构建公平和非公平的信号量
/**
* Creates a {@code Semaphore} with the given number of
* permits and the given fairness setting.
*
* @param permits the initial number of permits available.
* This value may be negative, in which case releases
* must occur before any acquires will be granted.
* @param fair {@code true} if this semaphore will guarantee
* first-in first-out granting of permits under contention,
* else {@code false}
*/
public Semaphore(int permits, boolean fair) {
sync = (fair)? new FairSync(permits) : new NonfairSync(permits);
}

FairSync 和 NonfairSync 继承Sync 类,然而Sync 类继承 AbstractQueuedSynchronizer
/**
* Synchronization implementation for semaphore. Uses AQS state
* to represent permits. Subclassed into fair and nonfair
* versions.
*/
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 1192457210091910933L;

Sync(int permits) {
setState(permits);
}

final int getPermits() {
return getState();
}

final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}

protected final boolean tryReleaseShared(int releases) {
for (;;) {
int p = getState();
if (compareAndSetState(p, p + releases))
return true;
}
}

final void reducePermits(int reductions) {
for (;;) {
int current = getState();
int next = current - reductions;
if (compareAndSetState(current, next))
return;
}
}

final int drainPermits() {
for (;;) {
int current = getState();
if (current == 0 || compareAndSetState(current, 0))
return current;
}
}
}

参考文献

Java并发编程
AbstractQueuedSynchronizer