cz.cuni.amis.utils.flag
Class Flag<T>
java.lang.Object
cz.cuni.amis.utils.flag.Flag<T>
- Type Parameters:
T
- type of the flag
- All Implemented Interfaces:
- IFlag<T>, java.io.Serializable
- Direct Known Subclasses:
- Connective, FlagInteger, FlagJMXProxy, ImmutableFlag, ReasonFlag
public class Flag<T>
- extends java.lang.Object
- implements IFlag<T>, java.io.Serializable
This class may be used to create an observable value (you may attach change-listeners to it).
This is flag class which is designed for Boolean or Integer types (but
it should work with other types as well as long as they have equals() implemented
correctly).
It allows you to store the state of flag and register listeners on the flag.
Note that the implementation is:
- thread-safe (truly),
- recursion-safe (meaning that the flag may be changed from within the listener it notifies of the flag changes - such events are put into the queue and processed in correct sequence),
- setters/getters are non-blocking (or they blocks for finite small amount of time ~ few synchronized statements used, which can't block each other for greater period of time).
Also note that can't be a really correct implementation of the flag that always returns
the right value - if you heavily use flag from let's say a tens of threads then there may
be glitches in the getFlag() returned value (but for the most implementation this value
will be correct in 99.99999%!).
Note that the implementation of notifying about flag-change is
strictly time-ordered. Every flag-change event is fully processed before another is raised/received.
There is a possibility that a listener on the flag change will attempt to change the flag again (mentioned recursion-safe).
In that case processing of this flag change is postponed until the previous event has been fully processed
(e.g. all listeners has been notified about it).
Last piece of magic - if you want to change the flag value in-sync (meaning that you need 100% safe reading of the flag value), instantiate Flag.DoInSync class
and submit it via inSync() method - Flag.DoInSync.execute(Object)
method will be executed in synchronized state so no one can change the flag value
while you're inside this method.
- See Also:
- Serialized Form
Nested Class Summary |
static class |
Flag.DoInSync<T>
Usage of this abstract class is as simple as it could be ... |
Constructor Summary |
Flag()
Initialize the flag with 'null' as an initial value. |
Flag(T initialValue)
Initialize the flag with 'initialValue'. |
Method Summary |
void |
addListener(FlagListener<T> listener)
Adds new listener to the flag with specified param. |
void |
addStrongListener(FlagListener<T> listener)
Adds new listener to the flag (strong reference). |
void |
clearListeners()
Call to clear (remove) all the listeners on the flag. |
void |
defreeze()
Method is synchronized. |
void |
freeze()
This method will freeze the processing of the setFlag() method. |
T |
getFlag()
Returns the value of the flag. |
ImmutableFlag<T> |
getImmutable()
|
void |
inSync(Flag.DoInSync<T> command)
Add a command (to the end of the queue) that will be executed in-sync with other changes (you may be sure that no other changes
are taking place right now). |
protected void |
inSyncInner(Flag.DoInSync<T> command,
boolean addAsFirst)
Add a command that will be executed in-sync with other changes (you may be sure that no other changes
are taking place right now). |
boolean |
isFrozen()
Whether the flag-change has been frozen, i.e., setFlag() won't change the flag value
immediately by will wait till defreeze() is called. |
boolean |
isListenning(FlagListener<T> listener)
Checks whether listener is already registered (using equals()). |
boolean |
isNone(T... oneOfTheValue)
Tells whether the flag is not set to anz of 'one of the values' passed. |
boolean |
isOne(T... oneOfTheValue)
Tells whether the flag is set to 'one of the values' passed. |
void |
removeAllListeners()
Removes all listeners. |
void |
removeListener(FlagListener<T> listener)
Removes all registered 'listener' from the flag. |
void |
setFlag(T newValue)
Changes the flag and informs all listeners. |
T |
waitFor(long timeoutMillis,
T... oneOfTheValue)
Pauses the thread till the flag is set from the outside to one of specified values or times out. |
T |
waitFor(T... oneOfTheValue)
Pauses the thread till the flag is set from the outside to one of specified values. |
T |
waitForChange()
Pauses the thread till the flag change to another value. |
T |
waitForChange(long timeoutMillis)
Pauses the thread till the flag change to another value or timeout. |
Methods inherited from class java.lang.Object |
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Flag
public Flag()
- Initialize the flag with 'null' as an initial value.
Flag
public Flag(T initialValue)
- Initialize the flag with 'initialValue'.
- Parameters:
initialValue
-
inSyncInner
protected void inSyncInner(Flag.DoInSync<T> command,
boolean addAsFirst)
- Add a command that will be executed in-sync with other changes (you may be sure that no other changes
are taking place right now).
This is also used by the setFlag() method.
- Parameters:
command
- addAsFirst
- if true the command will be added as a first to execute
inSync
public void inSync(Flag.DoInSync<T> command)
- Add a command (to the end of the queue) that will be executed in-sync with other changes (you may be sure that no other changes
are taking place right now).
This is also used by the setFlag() method.
- Specified by:
inSync
in interface IFlag<T>
- Parameters:
command
-
setFlag
public void setFlag(T newValue)
- Changes the flag and informs all listeners.
- Specified by:
setFlag
in interface IFlag<T>
- Parameters:
newValue
-
- Throws:
InterruptedRuntimeException
- if interrupted during the await on the freeze latch
isFrozen
public boolean isFrozen()
- Whether the flag-change has been frozen, i.e., setFlag() won't change the flag value
immediately by will wait till
defreeze()
is called.
- Specified by:
isFrozen
in interface IFlag<T>
freeze
public void freeze()
- This method will freeze the processing of the setFlag() method. Method is synchronized.
It waits until all setFlag() pending requests are resolved and then returns.
It may be used to for the synchronized registration of the listeners (if you really care
for the value of the flag before creating the listener). Or it may be used to obtain
a true value of the flag in the moment of the method call (as it waits for all the listeners
to execute).
In one of these cases, do this:
- flag.freeze()
-
- examine the flag value and/or register new listeners
- flag.defreeze() // DO NOT FORGET THIS!
Example: you have a flag that is counting how many alive threads you have, those threads may
be created concurrently ... without this synchronizing method you wouldn't be able to correctly
read the number of threads before incrementing the flag.
Beware of deadlocks when using this method, watch out:
a) infinite recursion during the setFlag() (listeners are changing the flag value repeatedly)
b) incorrect sequences of the freeze() / defreeze() calls
Of course you may simulate this behavior with simple synchronized() statement, but
this isn't always feasible as it blocks all other threads while accessing this flag,
note that this flag implementation promotes non-blocking methods.
- Specified by:
freeze
in interface IFlag<T>
defreeze
public void defreeze()
- Method is synchronized. See
freeze()
for info.
- Specified by:
defreeze
in interface IFlag<T>
waitForChange
public T waitForChange()
throws PogamutInterruptedException
- Pauses the thread till the flag change to another value.
- Returns:
- flag value that woke up the thread
- Throws:
PogamutInterrputedException
PogamutInterruptedException
waitForChange
public T waitForChange(long timeoutMillis)
throws PogamutInterruptedException
- Pauses the thread till the flag change to another value or timeout.
Returns null if times out, otherwise returns value that woke up the thread.
- Parameters:
timeoutMillis
- oneOfTheValue
-
- Returns:
- null (timeout) or value that woke up the thread
- Throws:
PogamutInterruptedException
waitFor
public T waitFor(T... oneOfTheValue)
throws PogamutInterruptedException
- Pauses the thread till the flag is set from the outside to one of specified values.
- Parameters:
oneOfTheValue
-
- Returns:
- flag value that woke up the thread
- Throws:
PogamutInterruptedException
waitFor
public T waitFor(long timeoutMillis,
T... oneOfTheValue)
throws PogamutInterruptedException
- Pauses the thread till the flag is set from the outside to one of specified values or times out.
Returns null if times out, otherwise returns value that woke up the thread.
- Parameters:
timeoutMillis
- oneOfTheValue
-
- Returns:
- null (timeout) or value that woke up the thread
- Throws:
PogamutInterruptedException
getFlag
public T getFlag()
- Returns the value of the flag.
Note that if the flag contains any set-flag pending requests queue it will return the last
value from this queue.
This has a big advantage for the multi-thread heavy-listener oriented designs.
Every time a listener is informed about the flag change it receives a new value of the flag
but additionally it may query the flag for the last value there will be set into it.
Note that if you use the Flag sparingly this mechanism won't affect you in 99.99999% of time.
Warning - this method won't return truly a correct value if you will use inSync() method because
this time we won't be able to obtain the concrete value of the flag after the DoInSync command
will be carried out - instead we return the first value we are aware of. Again this won't
affect you in any way (... but you should know such behavior exist ;-))
- Specified by:
getFlag
in interface IFlag<T>
- Returns:
- value of the flag
isOne
public boolean isOne(T... oneOfTheValue)
- Tells whether the flag is set to 'one of the values' passed.
- Parameters:
oneOfTheValue
-
- Returns:
isNone
public boolean isNone(T... oneOfTheValue)
- Tells whether the flag is not set to anz of 'one of the values' passed.
- Parameters:
oneOfTheValue
-
- Returns:
getImmutable
public ImmutableFlag<T> getImmutable()
- Specified by:
getImmutable
in interface IFlag<T>
- Returns:
- Immutable version of this flag, setFlag(T) method of such
a flag will raise an exception.
addStrongListener
public void addStrongListener(FlagListener<T> listener)
- Adds new listener to the flag (strong reference).
Using this method is memory-leak prone.
- Specified by:
addStrongListener
in interface IFlag<T>
- Parameters:
listener
-
addListener
public void addListener(FlagListener<T> listener)
- Adds new listener to the flag with specified param. It will weak-reference the listener so when
you drop the references to it, it will be automatically garbage-collected.
Note that all anonymous
listeners are not subject to gc() because they are reachable from within the object where they were
created.
- Specified by:
addListener
in interface IFlag<T>
- Parameters:
listener
-
removeListener
public void removeListener(FlagListener<T> listener)
- Removes all registered 'listener' from the flag.
- Specified by:
removeListener
in interface IFlag<T>
- Parameters:
listener
-
removeAllListeners
public void removeAllListeners()
- Removes all listeners.
- Specified by:
removeAllListeners
in interface IFlag<T>
isListenning
public boolean isListenning(FlagListener<T> listener)
- Checks whether listener is already registered (using equals()).
- Specified by:
isListenning
in interface IFlag<T>
- Parameters:
listener
-
- Returns:
- true if listener is already registered
clearListeners
public void clearListeners()
- Call to clear (remove) all the listeners on the flag.
Should be used when the flag isn't going to be used again
to allow GC to collect the listeners (for instance anonymous objects).
- Specified by:
clearListeners
in interface IFlag<T>