java资源竞争问题,理解Semaphore及其用法详解
Semaphore也是一个线程同步的辅助类,可以维护当前访问自身的线程个数,并提供了同步机制。使用Semaphore可以控制同时访问资源的线程个数,例如,实现一个文件允许的并发访问数。
Semaphore的主要方法摘要:
void acquire():从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。
void release():释放一个许可,将其返回给信号量。
int availablePermits():返回此信号量中当前可用的许可数。
boolean hasQueuedThreads():查询是否有线程正在等待获取。
代码示例:
/*
* 防止同一台服务器上同时有多个人预约同一资源的同一日期
* 形象解释: Semaphore机制类似一个服务大厅(最多容纳20人),这个服务大厅里面有多个服务窗口(每一天的资源场地):A、
* B、C,这个服务大厅最多能进来20个人,进来的人都需要在各自需要办理的服务窗口排队等待,只有等到上一个人离
* 开(释放信号)下一个人才能进入该服务窗口办理,但是各服务窗口之间是并行的互不影响。
*/
//用于控制访问量的信号变量,一次最多进入20个请求,按照先进先出许可
private static Semaphore bookLockCounter = new Semaphore(20,true);
try{
//同一个应用服务内只允许20个人同时进入资源预定排队,否则报系统忙,请稍候再试。
if(bookLockCounter.getQueueLength() >= 20 || bookLockCounter.tryAcquire(500,TimeUnit.MILLISECONDS) == false)
{
throw new TzException("System is busy, please try again later.");
}
Semaphore tmpSemaphore = null;
boolean hasPlanSemaphore = false; //记录成功获取信号,预定完成后需要释放
try
{
//获取当资源日期对应的信号
//用资源ID+日期来标识同一资源的同一日期,其他人在想预约这一资源就需要排队,但是预约其他资源的话就不用排队
Map.Entry<String,Semaphore> tmpSemaphoreObject = tzGDObject.getSemaphore(tzms_class_addr_defn_tid + "-" +date);
if(tmpSemaphoreObject == null || tmpSemaphoreObject.getKey() == null || tmpSemaphoreObject.getValue() == null)
{
//如果返回的信号灯为空,报系统忙,请稍后再试(一般不会)
throw new TzException("System is busy, please try again later.");
}else{
tmpSemaphore = tmpSemaphoreObject.getValue();
//通过获取的信号将每个资源日期并行执行,资源日期内串行执行
tmpSemaphore.acquire();
//获取信号灯标记,预定完成后需要释放
hasPlanSemaphore = true;
}
/*//////////////////////////////////////////////////////////////////////////////*/
/*/////////////////////此处开始执行预定的逻辑/////////////////////////////////////*/
/*//////////////////////////////////////////////////////////////////////////////*/
} catch(TzException e) {
e.printStackTrace();
//预定失败,失败信息获取:e.getMessage()
} finally {
//释放资源信号量
if(hasPlanSemaphore){
tmpSemaphore.release();
}
//释放信号量
bookLockCounter.release();
}
} catch(TzException e) {
e.printStackTrace();
}
其中tzGDObject类中:
// 用于将同一个服务上的并行访问串行化的信号灯映射变量
private static HashMap<String, Semaphore> semaphoreMap = new HashMap<String, Semaphore>();
// 用于将用于将同一个服务上的并行访问串行化的信号灯变量
private static Semaphore sequenceSemaphore = new Semaphore(1, true);
/**
* 获取调用者信息的方法
*/
private String getCallerName() {
String callerName = "";
StackTraceElement tmpstack[] = Thread.currentThread().getStackTrace();
boolean findFlag = false;
for (StackTraceElement stackitem : tmpstack) {
if ((stackitem.getClassName().indexOf(getClass().getName())) >= 0) {
findFlag = true;
} else if (findFlag == true) {
callerName = stackitem.getClassName() + "." + stackitem.getMethodName();
break;
}
}
return callerName;
}
/**
* 获取信号灯变量的方法
*/
public Map.Entry<String, Semaphore> getSemaphore(String semaphoreName) {
Semaphore tmpSemaphore = null;
String tmpSemaphoreName = getCallerName() + "-" + semaphoreName;
System.out.println("successfully get the traffic light variable name[Thread ID : "
+ Thread.currentThread().getId() + "]: " + tmpSemaphoreName);
if (semaphoreMap.containsKey(tmpSemaphoreName) == true) {
tmpSemaphore = semaphoreMap.get(tmpSemaphoreName);
} else {
try {
// 获取信号灯,同步线程
if (sequenceSemaphore.tryAcquire(100, TimeUnit.MILLISECONDS) == false) {
return null;
}
} catch (Exception e) {
return null;
}
// 再次判断一下指定的信号灯是否已创建
if (semaphoreMap.containsKey(tmpSemaphoreName) == true) {
tmpSemaphore = semaphoreMap.get(tmpSemaphoreName);
} else {
tmpSemaphore = new Semaphore(1, true);
semaphoreMap.put(tmpSemaphoreName, tmpSemaphore);
}
// 释放信号灯
sequenceSemaphore.release();
}
HashMap<String, Semaphore> tmpHashMap = new HashMap<String, Semaphore>();
tmpHashMap.put(tmpSemaphoreName, tmpSemaphore);
return tmpHashMap.entrySet().iterator().next();
}
/**
* 获取信号灯变量的方法,用于在两个不同的地方对同一个信号灯变量的控制,且调用该方法的参数相同
* @author zhanglang
* @param semaphoreKey
* @param semaphoreName
* @return
*/
public Map.Entry<String, Semaphore> getSemaphore(String semaphoreKey, String semaphoreName) {
Semaphore tmpSemaphore = null;
String tmpSemaphoreName = "MULTI_" + semaphoreKey + "-" + semaphoreName;
if (semaphoreMap.containsKey(tmpSemaphoreName) == true) {
tmpSemaphore = semaphoreMap.get(tmpSemaphoreName);
} else {
try {
// 获取信号灯,同步线程
if (sequenceSemaphore.tryAcquire(100, TimeUnit.MILLISECONDS) == false) {
return null;
}
} catch (Exception e) {
return null;
}
// 再次判断一下指定的信号灯是否已创建
if (semaphoreMap.containsKey(tmpSemaphoreName) == true) {
tmpSemaphore = semaphoreMap.get(tmpSemaphoreName);
} else {
tmpSemaphore = new Semaphore(1, true);
semaphoreMap.put(tmpSemaphoreName, tmpSemaphore);
}
// 释放信号灯
sequenceSemaphore.release();
}
HashMap<String, Semaphore> tmpHashMap = new HashMap<String, Semaphore>();
tmpHashMap.put(tmpSemaphoreName, tmpSemaphore);
return tmpHashMap.entrySet().iterator().next();
}
浙公网安备 33010602011771号