标签:
锁设计目的:
1 当db可以正常连接时,控制当前最大连接线程数量为6,最大的等待线程数为15,接下来线程如何的试图获取锁请求自己报异常。
2 设置锁等待时间,当等待线程超过该时间,自动释放锁。
3 当线程连接时间过长,超过5分钟,可视为db已经发生异常,将db 状态quitemode设为false,后续线程连接直接报异常
4 当db不可用时,直接返回false,且在规定时间段之后可以重试获取锁
锁实现:
1 使用类LockCounter来封装连接线程数,LockCounter放在ThreadLocal,封闭在线程里面。
2 使用reloadConfig定期更新配置
public class ServiceLock {
protected static final LogContext logger = LogContextFactory.singleton()
.getLogContext();
private static final ServiceLock instance = new ServiceLock();
// record lock information about current thread lock: nest number, locking
// spending time
private static ThreadLocal<LockCounter> currentThreadNestCount = new ThreadLocal<LockCounter>();
// lightweight synchronized, to replace java synchronized
private static Lock locksync = new ReentrantLock();
// when quietMode = ture, any locking action will return exception directly,
// means current SCODS is unavaliable.
private static volatile boolean quietMode = false;
// when quietMode = true, retry once in every quietModeRetryInterval time
// to detect if SCODS is working
private static long quietModeRetryInterval = 900;//seconds
// in quiet mode, update quietModeRefreshTimestamp to current time stamp
// before retry
private static volatile long quietModeRefreshTimestamp = 0;// seconds
// the last time when a thread get the lock successfully (means lockCount++)
private static volatile long lastLockTime = System.currentTimeMillis();
// the lock number which has already been used in lock pool,
// when a thread get a lock successfully, the lockCount will increase 1
// until reach the upper limit: maxLockCount
public volatile static int lockCount = 0;
// waitingCount indicate how many threads are waiting for opportunity to get
// lock from lock pool
// waitingCount also has a upper limit: maxWaitingCount
public volatile static int waitingCount = 0;
// max number of lock could be provided by lock pool
public static int maxLockCount = 6;
// max number of threads could be waiting lock to be released into lock pool
public static int maxWaitingCount = 15;
// waiting timeout seconds
public static int waitingTimeout = 30;// seconds
// if lock failed to be released in <quietModeDetectTime> seconds, that
// means SCODS is having issue now
public static int quietModeDetectTime = 300;//seconds
// refresh configuration interval
public volatile static int configReloadInterval = 1800; //seconds
// the last time the configuration being refreshed
public volatile static long configReloadTimestamp = 0;
public static ServiceLock getSingle() {
return ServiceLock.instance;
}
/**
* acquire a lock, if failed, throws
* ServiceLockAcquireFailedException this method have to be try catch
*
* @throws ServiceLockAcquireFailedException
*/
public static void lock() throws ServiceLockAcquireFailedException {
ServiceLock.getSingle().locking();
}
/**
* release a lock after using, this method has to be in finally sectionF
*/
public static void unLock() {
ServiceLock.getSingle().unLocking();
}
public boolean getQuietMode() {
return quietMode;
}
private void reloadConfig() {
boolean needRefreshConfig = false;
try {
locksync.lock();
if ((System.currentTimeMillis() - configReloadTimestamp) > configReloadInterval * 1000) {
needRefreshConfig = true;
configReloadTimestamp = System.currentTimeMillis();
}
} catch (Throwable t) {
// do nothing
} finally {
locksync.unlock();
}
if (needRefreshConfig) {
debug("ServiceLock reloading config");
try {
Map<String, String> config = QuoteProcessFactory.singleton()
.create().refreshSCODSConnPoolConfig();
String value = config.get("PORETRYINTERVAL");
if (StringUtils.isNotBlank(value)) {
quietModeRetryInterval = Integer.valueOf(value.trim());
System.out.println("ServiceLock config reload quietModeRetryInterval -> "
+ quietModeRetryInterval);
}
value = config.get("POLOCKPOOLMAX");
if (StringUtils.isNotBlank(value)) {
maxLockCount = Integer.valueOf(value.trim());
System.out.println("ServiceLock config reload maxLockCount -> "
+ maxLockCount);
}
value = config.get("POWAITINGMAX");
if (StringUtils.isNotBlank(value)) {
maxWaitingCount = Integer.valueOf(value.trim());
System.out.println("ServiceLock config reload maxWaitingCount -> "
+ maxWaitingCount);
}
value = config.get("POWAITTIMEOUT");
if (StringUtils.isNotBlank(value)) {
waitingTimeout = Integer.valueOf(value.trim());
System.out.println("ServiceLock config reload waitingTimeout -> "
+ waitingTimeout);
}
value = config.get("POQUIETDECTTIME");
if (StringUtils.isNotBlank(value)) {
quietModeDetectTime = Integer.valueOf(value.trim());
System.out.println("ServiceLock config reload quietModeDetectTime -> "
+ quietModeDetectTime);
}
value = config.get("POCONFIGRELOADINTER");
if (StringUtils.isNotBlank(value)) {
configReloadInterval = Integer.valueOf(value.trim());
System.out.println("ServiceLock config reload configReloadInterval -> "
+ configReloadInterval);
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}
public void locking() throws ServiceLockAcquireFailedException {
System.out.println("ServiceLock Thread[" + Thread.currentThread() + "("
+ Thread.currentThread().getId() + ")] is acquiring lock...");
reloadConfig();
LockCounter count = currentThreadNestCount.get();
if (count == null) {// the first time current thread is acquiring lock,
// not nest invoking
count = new LockCounter();
currentThreadNestCount.set(count);
} else if (count.getCount() > 0) {// if count>0, means nest invoking,
// don‘t need to acquire new lock
count.inc();
return;
}
boolean waiting = false;// this is a flag to indicate if this locking
// request has to wait when lock pool is empty
try {
locksync.lock();
if (!quietMode
&& lockCount > 0
&& ((System.currentTimeMillis() - lastLockTime) > quietModeDetectTime * 1000)) {
// if lock failed to be released to lock pool
// timely(>quietModeDetectTime), SCODS maybe experiencing issue,
// our lock pool needs to become quiet mode, which means any
// locking request will get failed to avoid high DB connection
// disaster.
quietMode = true;
quietModeRefreshTimestamp = System.currentTimeMillis();
System.out.println("ServiceLock Thread[" + Thread.currentThread()
+ "(" + Thread.currentThread().getId()
+ ")] is going into quiet mode. lastLockTime -> "
+ lastLockTime + " currentTimeMillis -> "
+ System.currentTimeMillis());
}
if (quietMode
&& ((System.currentTimeMillis() - quietModeRefreshTimestamp) > quietModeRetryInterval * 1000)) {
// in quiet mode, have to detect if SCODS is working again in
// each quietModeRetryInterval seconds
lockCount++;
count.inc();
lastLockTime = System.currentTimeMillis();
quietModeRefreshTimestamp = System.currentTimeMillis();
System.out.println("ServiceLock Thread[" + Thread.currentThread()
+ "(" + Thread.currentThread().getId()
+ ")] is retrying once in quiet mode");
return;
} else if (quietMode) {
throw new ServiceLockAcquireFailedException(
"ServiceLock is in quiet mode");
}
if (waitingCount >= maxWaitingCount) {
// waiting pool is full, return exception directly
throw new ServiceLockAcquireFailedException(
"ServiceLock over max waiting count");
}
if (waitingCount > 0 || lockCount >= maxLockCount) {
// lock pool is empty, thread has to wait until lock is released
waitingCount++;
waiting = true;
} else {
// thread is getting lock successfully
lockCount++;
count.inc();
lastLockTime = System.currentTimeMillis();
System.out.println("ServiceLock Thread[" + Thread.currentThread()
+ "(" + Thread.currentThread().getId()
+ ")] has got lock successfully");
return;
}
} catch (ServiceLockAcquireFailedException e) {
throw e;
} catch (Throwable t) {
throw new RuntimeException(t);
} finally {
locksync.unlock();
}
if (waiting) {
System.out.println("ServiceLock Thread[" + Thread.currentThread() + "("
+ Thread.currentThread().getId() + ")] is waiting lock...");
long waitingStartTime = System.currentTimeMillis();
for (; !quietMode;) {// loop to get available lock, unless getting
// into quiet mode
try {
locksync.lock();
if (lockCount < maxLockCount) {
lockCount++;
count.inc();
lastLockTime = System.currentTimeMillis();
waitingCount--;
if (waitingCount < 0)
waitingCount = 0;
System.out.println("ServiceLock Thread["
+ Thread.currentThread() + "("
+ Thread.currentThread().getId()
+ ")] fianlly got lock after waiting");
return;
}
} catch (Throwable t) {
// do nothing
} finally {
locksync.unlock();
}
if ((System.currentTimeMillis() - waitingStartTime) % 10000 > 2000) {
// to avoid high CPU consuming, the loop sequence will keep
// high in 2 seconds and lower in next 8 seconds
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// do nothing
}
} else {
// don‘t sleep, full speed loop;
}
if ((System.currentTimeMillis() - waitingStartTime) > waitingTimeout * 1000) {
// waiting timeout, throw exception in the end
break;
}
}
waitingCount--;
if (waitingCount < 0)
waitingCount = 0;
throw new ServiceLockAcquireFailedException(
"ServiceLock wait timeout to aquire lock");
}
}
public void unLocking() {
LockCounter count = currentThreadNestCount.get();
if (count != null && count.getCount() > 0) {
// current thread actually got lock successfully
long spendTime = count.dec();
if (count.getCount() == 0) {
try {
locksync.lock();
lockCount--;
if (quietMode && spendTime < quietModeDetectTime * 1000) {
// in quiet mode, if lock is released in time (within
// quietModeDetectTime seconds), means SCODS is working
// fine now. So cancel quiet mode, clear lock pool
quietMode = false;
quietModeRefreshTimestamp = System.currentTimeMillis();
lockCount = 0;
System.out.println("ServiceLock Thread["
+ Thread.currentThread()
+ "("
+ Thread.currentThread().getId()
+ ")] released lock and set quietMode false successfuly");
} else if (quietMode) {
System.out.println("ServiceLock Thread["
+ Thread.currentThread()
+ "("
+ Thread.currentThread().getId()
+ ")] released lock but can‘t set quietMode false");
}
System.out.println("ServiceLock Thread["
+ Thread.currentThread() + "("
+ Thread.currentThread().getId()
+ ")] released lock");
} catch (Throwable t) {
// do nothing
} finally {
locksync.unlock();
}
}
}
}
class LockCounter {
// the number re-acquire lock in one thread
private int count = 0;
// the time stamp when lock is acquired
private long startTime = System.currentTimeMillis();
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
// increasing count
public void inc() {
if (count == 0) {
startTime = System.currentTimeMillis();
}
this.count++;
}
// decreasing count, return spending time after start locking time
public long dec() {
this.count--;
if (this.count < 0) {
this.count = 0;
}
return System.currentTimeMillis() - startTime;
}
}
// private void log() {
// System.out.println("lockCount: " + ServiceLock.lockCount
// + " waitingCount: " + ServiceLock.waitingCount + " ");
// }
}
标签:
原文地址:http://www.cnblogs.com/xiongjianjunjava/p/4329877.html