Mercurial Hosting > nabble
diff src/fschmidt/util/locks/TimedLock.java @ 68:00520880ad02
add fschmidt source
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Sun, 05 Oct 2025 17:24:15 -0600 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/fschmidt/util/locks/TimedLock.java Sun Oct 05 17:24:15 2025 -0600 @@ -0,0 +1,173 @@ +/* +Copyright (c) 2008 Franklin Schmidt <fschmidt@gmail.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +package fschmidt.util.locks; + +import java.util.Set; +import java.util.HashSet; +import java.util.Collections; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Lock; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public final class TimedLock extends ProxyLock { + private static final Logger logger = LoggerFactory.getLogger(TimedLock.class); + + private static long timeoutDefault = 10L*60L*1000L; // 10 minutes + private static long waitTimeDefault = 60L*1000L; // 1 minutes + + public static long getTimeoutDefault() { + return timeoutDefault; + } + + public static void setTimeoutDefault(long timeoutDefault) { + TimedLock.timeoutDefault = timeoutDefault; + } + + public static long getWaitTimeDefault() { + return waitTimeDefault; + } + + public static void setWaitTimeDefault(long waitTimeDefault) { + TimedLock.waitTimeDefault = waitTimeDefault; + } + + private static Set<TimedLock> locks = Collections.synchronizedSet(new HashSet<TimedLock>()); + private int count = 0; + private final Object sync = new Object(); + private long whenLocked; + private long whenChecked; + private long timeout = timeoutDefault; + private long waitTime = waitTimeDefault; + private Thread thread = null; + + public TimedLock(Lock lock) { + super(lock); + } + + public long getTimeout() { + return timeout; + } + + public void setTimeout(long timeout) { + this.timeout = timeout; + } + + public long getWaitTime() { + return waitTime; + } + + public void setWaitTime(long waitTime) { + this.waitTime = waitTime; + } + + private void locked() { + synchronized(sync) { + if( count++ == 0 ) { + whenLocked = System.currentTimeMillis(); + whenChecked = whenLocked; + thread = Thread.currentThread(); + if( !locks.add(this) ) + throw new RuntimeException(); + } + } + } + + public boolean tryLock() { + if( !super.tryLock() ) + return false; + locked(); + return true; + } + + public boolean tryLock(long time,TimeUnit unit) + throws InterruptedException + { + long t = TimeUnit.MILLISECONDS.convert(time,unit); + while( t > waitTime ) { + if( super.tryLock(waitTime,TimeUnit.MILLISECONDS) ) { + locked(); + return true; + } + t -= waitTime; + check(); + } + if( super.tryLock(t,TimeUnit.MILLISECONDS) ) { + locked(); + return true; + } + return false; + } + + public void lockInterruptibly() + throws InterruptedException + { + while(true) { + if( super.tryLock(waitTime,TimeUnit.MILLISECONDS) ) { + locked(); + return; + } + check(); + } + } + + public void lock() { + try { + lockInterruptibly(); + } catch(InterruptedException e) { + throw new RuntimeException(e); + } + } + + public void unlock() { + synchronized(sync) { + if( --count == 0 ) { + if( !locks.remove(this) ) + throw new RuntimeException(); + thread = null; + } + } + super.unlock(); + } + + private void check() { + long now = System.currentTimeMillis(); + long tooOld = now - timeout; + TimedLock[] a = locks.toArray(new TimedLock[0]); + for( int i=0; i<a.length; i++ ) { + TimedLock tl = a[i]; + if( tl.whenChecked < tooOld ) { + StringBuilder buf = new StringBuilder(); + buf.append("lock "+tl+" timed out, locked for "+(System.currentTimeMillis()-tl.whenLocked)+" millis"); + buf.append("\n"+tl.thread); + for( StackTraceElement ste : tl.thread.getStackTrace() ) { + buf.append("\n\t"+ste); + } + logger.error(buf.toString()); + tl.whenChecked = now; + } + } + } + +}