001: /* WaitLock.java
002:
003: {{IS_NOTE
004: Purpose:
005:
006: Description:
007:
008: History:
009: Wed Mar 2 10:55:54 2005, Created by tomyeh
010: }}IS_NOTE
011:
012: Copyright (C) 2005 Potix Corporation. All Rights Reserved.
013:
014: {{IS_RIGHT
015: This program is distributed under GPL Version 2.0 in the hope that
016: it will be useful, but WITHOUT ANY WARRANTY.
017: }}IS_RIGHT
018: */
019: package org.zkoss.util;
020:
021: import org.zkoss.lang.SystemException;
022: import org.zkoss.lang.PotentialDeadLockException;
023:
024: /**
025: * A simple lock used to implement load-on-deman mechanism.
026: * Typical use: a thread, say A, checks whether a resource is loaded, and
027: * put a WaitLock instance if not loaded yet. Then, another thread, say B,
028: * if find WaitLock, it simply calls {@link #waitUntilUnlock} to wait.
029: * Meanwhile, once A completes the loading, it put back the resouce
030: * and calls {@link #unlock}.
031: *
032: * <pre><code>WaitLock lock = null;
033: for (;;) {
034: synchronized (map) {
035: Object o = map.get(key);
036: if (o == null) {
037: map.put(key, lock = new WaitLock());
038: break; //go to load resource
039: }
040: }
041: if (o instanceof MyResource)
042: return (MyResource)o;
043: if (!((Lock)o).waitUntilUnlock(60000))
044: log.waring("Takes too long");
045: }
046: //load resource
047: try {
048: ....
049: synchronized (map) {
050: map.put(key, resource);
051: }
052: return resource;
053: } catch (Throwable ex) {
054: synchronized (map) {
055: map.remove(key);
056: }
057: throw SystemException.Aide.wrap(ex);
058: } finally {
059: lock.unlock();
060: }
061: </code></pre>
062: *
063: * Refer to i3sys's SketchPostImpl, zweb's JspLoaderServlet for examples.
064: *
065: * @author tomyeh
066: */
067: public class WaitLock {
068: private final Thread _locker = Thread.currentThread();
069: private boolean _unlocked;
070:
071: /** Once created, it is default to be locked.
072: * In other words, other thread's invocation of {@link #waitUntilUnlock}
073: * won't return until {@link #unlock} is called.
074: */
075: public WaitLock() {
076: }
077:
078: /** Waits this lock to unlock.
079: *
080: * @return whether it is unlocked successfully
081: * @exception SystemException if this thread is interrupted
082: * @exception PotentialDeadLockException if the thread itself creates
083: * this lock. In other words, it tried to wait for itself to complete.
084: */
085: synchronized public boolean waitUntilUnlock(int timeout) {
086: if (!_unlocked) {
087: if (Thread.currentThread().equals(_locker))
088: throw new PotentialDeadLockException("Wait for itself?");
089: try {
090: this .wait(timeout);
091: } catch (InterruptedException ex) {
092: throw SystemException.Aide.wrap(ex);
093: }
094: }
095: return _unlocked;
096: }
097:
098: /** Unlocks any other threads blocked by {@link #waitUntilUnlock}.
099: */
100: synchronized public void unlock() {
101: _unlocked = true;
102: this .notifyAll(); //wake up all pending
103: }
104: }
|