just to clarify - the volatile in that link referred to C language
'volatile' keyword that happened to be used in the JDK native
implementation of park(), unpark() routines. C language 'volatile'
only prevents compiler optimizations - it doesn't apply memory
barriers after/before load/store.

i remember we had a terrible lost interrupt in hdfs once that was
similar to this problem (as ryan finally described it).

On Thu, Apr 15, 2010 at 3:28 PM, Kannan Muthukkaruppan
<kan...@facebook.com> wrote:
> Ryan:
>
> Joy had brought up a related issue to attention recently, and fwd'ed this 
> link:
>
> http://blogs.sun.com/dave/entry/a_race_in_locksupport_park
>
> It has to do with a volatile "_counter" variable as well.
>
> From the above writeup:
>
> <<< The problem would only manifest when we were using the -UseMembar 
> optimization that lets us remove fences from certain hot thread state 
> transitions paths that need to coordinate safepoints between mutator threads 
> and the JVM. This feature is enabled by default, but we can turn it off with 
> the -XX:+UseMembar switch, which causes the JVM to emit normal fence 
> instructions in the state transitions paths. (That particular optimization is 
> an example of asymmetric Dekker synchronization). Crucially, the park() path 
> contains such a state transition. In reality the fence emitted by the 
> +UseMembar switch was simply covering up the otherwise latent Parker:: bug. 
> +UseMembar constitutes a work-around. Sensitivity to UseMembar was initially 
> confounding but ultimately a valuable clue.>>>
>
>
> -----Original Message-----
> From: Dhruba Borthakur [mailto:dhr...@gmail.com]
> Sent: Thursday, April 15, 2010 3:24 PM
> To: hbase-dev@hadoop.apache.org
> Subject: Re: volatile considered harmful
>
> I agree. The Java spec clearly mentions that load/store/read/write to
> volatile are atomic
>
> http://java.sun.com/docs/books/jls/second_edition/html/memory.doc.html#28330
>
> <http://java.sun.com/docs/books/jls/second_edition/html/memory.doc.html#28330>but
> definitely not increment and decrement. increment and decrement operations
> need to load *and* store data to a volatile variable and are not atomic.
>
> -dhruba
>
>
> On Thu, Apr 15, 2010 at 3:00 PM, Ryan Rawson <ryano...@gmail.com> wrote:
>
>> So there I was, running a unit test.  I step away and hours later it
>> still had not finished.  It was stuck on this line of the code:
>>
>>      putThread.done();
>> >    putThread.join();
>>
>> So the putThread was not finishing as it was supposed to do.  Well,
>> what does putThread.done() do:
>>
>>    public void done() {
>>      done = true;
>>      synchronized (this) {
>>        interrupt();
>>      }
>>    }
>>
>>
>> Looks reasonable, wait, what is this access of a variable shared among
>> multiple threads outside of a sync block?  Oh wait, its "ok", it's
>> volatile:
>>
>>    private volatile boolean done;
>>
>>
>> And what does the run loop of the thread look like?  Again reasonable:
>>
>>    public void run() {
>>      done.set(false);
>>      int val = 0;
>>      while (!done.get()) {
>>       // Do HRegion.put call with some exception handling
>>      }
>>    }
>>
>>
>> Well in theory this all looks reasonable.
>>
>> But why harmful?
>>
>> I had changed the Gets to not acquire row locks, thus removing a
>> synchronization block between the main thread (which did Gets and then
>> eventually called that code up top).  Two consequences, one was puts
>> happened much faster (good!), and a negative consequence is sometimes
>> the test would fail to stop the put thread.  For minutes and hours
>> after the main thread had signalled the put thread to stop, it still
>> had not.
>>
>> I switched the volatile boolean => AtomicBoolean and the problem went away.
>>
>> In short, the use of volatile is not guaranteed to see an update from
>> a different thread in any timely manner. The Java Memory Model does
>> not ensure this.  If you need to rely on passing data between threads
>> you need to either use a monitor lock (using synchronized keyword
>> either at the method level or as an explicit block) or use one of the
>> concurrent utilities classes - such as AtomicLong, AtomicBoolean, or
>> the excellent read/write locks.
>>
>> If you wish to increment a counter from multiple threads, doing this:
>> volatile int count = 0;
>> // later:
>> count++;
>>
>> will not work.  You must use an AtomicInt/Long or use a monitor lock.
>> This is because the operation "count++" is not atomic, it is actually
>> 3 - get, add, put.
>>
>> As we code in HBase, we should avoid the use of volatile as much as
>> possible.  The guarantees it makes are not good enough and can cause a
>> lot of pain figuring this out months after you originally coded it.
>>
>
>
>
> --
> Connect to me at http://www.facebook.com/dhruba
>
>

Reply via email to