|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 5 of 7
Listing 2 shows a simple implementation of such a beast. There's not much to it -- the vast majority of the file is comments.
The main thing is the _is_true flag declared at the top of the class. The _is_true flag stores the state of the condition variable. You can set the condition to true or false by calling set_true() or set_false(). You can test the current state without blocking by calling is_true() or is_false(). You can block, waiting for the condition to become true by calling wait_for_true(), which doesn't block at all if the condition happens to be true when you call it.
001 | package com.holub.asynch;
002 |
003 | //-------------------------------------------------------
004 | // This code (c) 1998 Allen I. Holub. All rights reserved.
005 | //-------------------------------------------------------
006 | // This code may not be distributed by yourself except in binary form,
007 | // incorporated into a Java .class file. You may use this code freely
008 | // for personal purposes, but you may not incorporate it into any
009 | // commercial product without express permission of Allen I. Holub in writing.
010 | //-------------------------------------------------------
011 |
012 | /**
013 | * This class implements a simple "condition variable." The notion
014 | * is that a thread waits for some condition to become true.
015 | * If the condition is false, then no wait occurs.
016 | *
017 | * Be very careful of nested-monitor-lockout here:
018 | * <PRE>
019 | * class lockout
020 | * { Condition godot = new Condition(false);
021 | *
022 | * synchronized void f()
023 | * {
024 | * some_code();
025 | * godot.wait_for_true();
026 | * }
027 | *
028 | * synchronized void set() // Deadlock if another thread is in f()
029 | * { godot.set_true();
030 | * }
031 | * }
032 | * </PRE>
033 | * You enter f(), locking the monitor, then block waiting for the
034 | * condition to become true. Note that you have not released the
035 | * monitor for the "lockout" object. [The only way to set godot true
036 | * is to call set(), but you'll block on entry to set() because
037 | * the original caller to f() has the monitor containing "lockout"
038 | * object.]
039 | * <p>Solve the problem by releasing the monitor before waiting:
040 | * <PRE>
041 | * class okay
042 | * { Condition godot = new Condition(false);
043 | *
044 | * void f()
045 | * { synchronized( this )
046 | * { some_code();
047 | * }
048 | * godot.wait_for_true(); // Move the wait outside the monitor
049 | * }
050 | *
051 | * synchronized void set()
052 | * { godot.set_true();
053 | * }
054 | * }
055 | * </PRE>
056 | * or by not synchronizing the `set()` method:
057 | * <PRE>
058 | * class okay
059 | * { Condition godot = new Condition(false);
060 | *
061 | * synchronized void f()
062 | * { some_code();
063 | * godot.wait_for_true();
064 | * }
065 | *
066 | * void set() // Remove the synchronized statement
067 | * { godot.set_true();
068 | * }
069 | * }
070 | * </PRE>
071 | * The normal wait()/notify() mechanism doesn't have this problem since
072 | * wait() releases the monitor, but you can't always use wait()/notify().
073 | */
074 |
075 |
076 | public class Condition
077 | {
078 | private boolean _is_true;
079 |
080 | /** Create a new condition variable in a known state.
081 | */
082 | public Condition( boolean is_true ){ _is_true = is_true; }
083 |
084 | /** See if the condition variable is true (without releasing).
085 | */
086 | public synchronized boolean is_true() { return _is_true; }
087 |
088 | /** Set the condition to false. Waiting threads are not affected.
089 | */
090 | public synchronized void set_false(){ _is_true = false; }
091 |
092 | /** Set the condition to true. Waiting threads are not released.
093 | */
094 | public synchronized void set_true() { _is_true = true; notifyAll(); }
095 |
096 | /** Release all waiting threads without setting the condition true
097 | */
098 | public synchronized void release_all(){ notifyAll(); }
099 |
100 | /** Release one waiting thread without setting the condition true
101 | */
102 | public synchronized void release_one(){ notify(); }
103 |
104 | /** Wait for the condition to become true.
105 | * @param timeout Timeout in milliseconds
106 | */
107 | public synchronized void wait_for_true( long timeout )
108 | throws InterruptedException
109 | { if( !_is_true )
110 | wait( timeout );
111 | }
112 |
113 | /** Wait (potentially forever) for the condition to become true.
114 | */
115 | public synchronized void wait_for_true() throws InterruptedException
116 | { if( !_is_true )
117 | wait();
118 | }
119 | }
|
Listing 3 below is basically Listing 1 rewritten to use a Condition object. Now, a call to read_line() after the user enters the text works just fine because the condition will be in the true state, and wait_for_true() won't block. Notice that read_line() has to explicitly set the condition back to false after it has read the line.