001: /**
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */package com.tc.util.concurrent;
004:
005: import com.tc.exception.TCInternalError;
006:
007: import java.io.Serializable;
008:
009: /**
010: * A class to model a flag that can be set once and only once If you have a boolean in class that should
011: * really only be set once and only once (like a shutdown flag maybe), using this class might help your class stay
012: * implemented correctly <br>
013: * <br>
014: * NOTE: There is purposefully no way to reset the flag. Use of this class is meant to communicate that a particular
015: * flag should be set once and only once (period). <br>
016: * NOTE(2): This class is a lot like a latch in some ways (ie. it can only be set once and not reset). Unlike a latch,
017: * the set() method here is only allowed to be called once (ever). Additionally, there are no wait() style methods on
018: * this flag class
019: *
020: * @author teck
021: */
022: public final class SetOnceFlag implements Serializable {
023: // XXX: review Serialization semantics. Is it possible to get a SetOnceFlag that can be
024: // reset (ie. via serialize/deserialize)
025:
026: private final Object lock = new LockObject(); // use a private internal lock for good measure
027:
028: private volatile boolean set;
029:
030: public SetOnceFlag() {
031: this (false);
032: }
033:
034: /**
035: * Create a new SetOnceFlag, optionally <code>set()</code> 'ing the flag immediately
036: *
037: * @param setFlag true if the flag should be created already <code>set()</code>
038: */
039: public SetOnceFlag(final boolean setFlag) {
040: if (setFlag) {
041: this .set = true;
042: }
043: }
044:
045: /**
046: * Attempt to set the flag
047: *
048: * @return true if the flag was set, false otherwise
049: * @throws IllegalArgumentException if the value has already been set by a different thread
050: */
051: public void set() {
052: synchronized (lock) {
053: if (set) {
054: throw new IllegalStateException(
055: "Flag has already been set");
056: } else {
057: set = true;
058: }
059: }
060: }
061:
062: /**
063: * Attempt to atomically set the flag. This differs from <code>set()</set> in that
064: * it doesn't throw an exception if the value has already been set. This method
065: * is useful for flags that might be set more than once, but should act as a guard
066: * against path(s) that should only ever run once.
067: *
068: * NOTE: It is probably almost always wrong to ignore the return value of this method
069: *
070: * @return true iff this invocation actually set the flag, false otherwise
071: */
072: public boolean attemptSet() {
073: try {
074: synchronized (lock) {
075: if (set) {
076: return false;
077: }
078:
079: set();
080:
081: return set;
082: }
083: } catch (Throwable t) {
084: // this REALLY shouldn't happen, this would be a programming error
085: throw new TCInternalError(t);
086: }
087: }
088:
089: /**
090: * Has the flag been already set? README: This is example of how <b>NOT </b> to use this class: <br>
091: *
092: * <pre>
093: * if (!flag.isSet()) {
094: * flag.set();
095: *
096: * // ... do some protected, assumed one-time actions
097: * }
098: * </pre>
099: *
100: * This example code is broken becuase there is no synchronization and/or checking the return value of
101: * <code>set()</code>. It is certainly possible that two threads could execute the body of the <code>if</code>
102: * block A correct implementation might be: <br>
103: *
104: * <pre>
105: * if (flag.attemptSet()) {
106: * // do one time only actions
107: * } else {
108: * // flag was already set
109: * }
110: * </pre>
111: *
112: * @return true if the flag is already set
113: */
114: public boolean isSet() {
115: return set;
116: }
117:
118: public String toString() {
119: return "set: " + set;
120: }
121:
122: // java.lang.Object isn't Serializable, so use this silly class as a workaround
123: private static class LockObject extends java.lang.Object implements
124: Serializable {
125: // nada
126: }
127:
128: }
|