Discussion:
setting max value atomically
Ted Yu
2014-02-25 04:00:29 UTC
Permalink
Hi,
Given the following code (in multi-threaded environment):
    else if (maximumTimestamp < timestamp) {
      maximumTimestamp = timestamp;
    }

AtomicLong#compareAndSet can only update value based on equality.

Is there some way where the max can be set without adding synchronized keyword to the method ?

Thanks
Ted Yu
2014-02-25 04:01:14 UTC
Permalink
Hi,
Given the following code (in multi-threaded environment):
    else if (maximumTimestamp < timestamp) {
      maximumTimestamp = timestamp;
    }

AtomicLong#compareAndSet can only update value based on equality.

Is there some way where the max can be set without adding synchronized keyword to the method ?

Thanks
Mat Gessel
2014-02-25 05:13:16 UTC
Permalink
Looks like the Java 8 Accumulators are intended for such a scenario. You
pass a comparison function to the Accumulator and let it deal with
concurrency.
The function is applied with the current value as its first argument,
and the given update as the second argument. For example, to maintain
a running maximum value, you could supply Long::max along with
Long.MIN_VALUE as the identity.
http://download.java.net/jdk8/docs/api/java/util/concurrent/atomic/LongAccumulator.html

Not sure on the lambda the syntax, but it should be something like this:
LongAccumulator timestampMax = new LongAccumulator((x, y) -> (x > y) ? x :
y, 0L);
...
timestampMax.accumulate(timestamp);

-= Mat
Hi,
else if (maximumTimestamp < timestamp) {
maximumTimestamp = timestamp;
}
AtomicLong#compareAndSet can only update value based on equality.
Is there some way where the max can be set without adding synchronized
keyword to the method ?
Thanks
--
Mat Gessel
http://www.asquare.net
dev danke
2014-02-25 05:19:16 UTC
Permalink
Java 8 FTW!

Here's a nice in-depth article about Java synchronization in practice.
http://javarevisited.blogspot.com/2011/04/synchronization-in-java-synchronized.html
Post by Mat Gessel
Looks like the Java 8 Accumulators are intended for such a scenario. You
pass a comparison function to the Accumulator and let it deal with
concurrency.
The function is applied with the current value as its first argument,
and the given update as the second argument. For example, to maintain
a running maximum value, you could supply Long::max along with
Long.MIN_VALUE as the identity.
http://download.java.net/jdk8/docs/api/java/util/concurrent/atomic/LongAccumulator.html
LongAccumulator timestampMax = new LongAccumulator((x, y) -> (x > y) ? x
: y, 0L);
...
timestampMax.accumulate(timestamp);
-= Mat
Hi,
else if (maximumTimestamp < timestamp) {
maximumTimestamp = timestamp;
}
AtomicLong#compareAndSet can only update value based on equality.
Is there some way where the max can be set without adding synchronized
keyword to the method ?
Thanks
--
Mat Gessel
http://www.asquare.net
Eric Jain
2014-02-25 04:19:26 UTC
Permalink
Post by Ted Yu
else if (maximumTimestamp < timestamp) {
maximumTimestamp = timestamp;
}
AtomicLong#compareAndSet can only update value based on equality.
Is there some way where the max can be set without adding synchronized keyword to the method ?
How about:

for (long max = maximumTimestamp.get(); max < timestamp; max =
maximumTimestamp.get()) {
maximumTimestamp.compareAndSet(max, timestamp);
}
--
Eric Jain
zenobase.com -- What do you want to track today?


------------------------------------

Yahoo Groups Links

<*> To visit your group on the web, go to:
http://groups.yahoo.com/group/seajug/

<*> Your email settings:
Individual Email | Traditional

<*> To change settings online go to:
http://groups.yahoo.com/group/seajug/join
(Yahoo! ID required)

<*> To change settings via email:
seajug-digest-***@public.gmane.org
seajug-fullfeatured-***@public.gmane.org

<*> To unsubscribe from this group, send an email to:
seajug-unsubscribe-***@public.gmane.org

<*> Your use of Yahoo Groups is subject to:
http://info.yahoo.com/legal/us/yahoo/utos/terms/
dev danke
2014-02-25 05:03:27 UTC
Permalink
Eric: In my opinion, your suggestion of using a for-loop does not prevent a
race condition.

Ted: A small synchronized block, that encloses the compare and set
operations, is a reasonable solution to this problem. This is the same
type of logic that happens inside a compareAndSet() method.

synchronized(maximumTimestamp)
{
if (maximumTimestamp < timestamp)
{
maximumTimestamp = timestamp;
}
}
Post by Ted Yu
Post by Ted Yu
else if (maximumTimestamp < timestamp) {
maximumTimestamp = timestamp;
}
AtomicLong#compareAndSet can only update value based on equality.
Is there some way where the max can be set without adding synchronized
keyword to the method ?
for (long max = maximumTimestamp.get(); max < timestamp; max =
maximumTimestamp.get()) {
maximumTimestamp.compareAndSet(max, timestamp);
}
--
Eric Jain
zenobase.com -- What do you want to track today?
Eric Jain
2014-02-25 05:18:27 UTC
Permalink
Eric: In my opinion, your suggestion of using a for-loop does not prevent a race condition.
How so? We just compare-and-set until the maximum timestamp is equal
to or larger than our timestamp.

--
Eric Jain
zenobase.com -- What do you want to track today?


------------------------------------

Yahoo Groups Links

<*> To visit your group on the web, go to:
http://groups.yahoo.com/group/seajug/

<*> Your email settings:
Individual Email | Traditional

<*> To change settings online go to:
http://groups.yahoo.com/group/seajug/join
(Yahoo! ID required)

<*> To change settings via email:
seajug-digest-***@public.gmane.org
seajug-fullfeatured-***@public.gmane.org

<*> To unsubscribe from this group, send an email to:
seajug-unsubscribe-***@public.gmane.org

<*> Your use of Yahoo Groups is subject to:
http://info.yahoo.com/legal/us/yahoo/utos/terms/
dev danke
2014-02-25 05:39:06 UTC
Permalink
Does the for-loop approach guarantee that the same thread doing the
for-loop test "max =
maximumTimestamp.get()" is the same thread calling compareAndSet()?

I think a thread A doing the for-loop test could get suspended at that
point, and then another thread B with a different timestamp value could
make it through the whole for-loop, before the suspended thread A is awoken.

That doesn't seem thread-safe to me.
Post by dev danke
Eric: In my opinion, your suggestion of using a for-loop does not
prevent a race condition.
How so? We just compare-and-set until the maximum timestamp is equal
to or larger than our timestamp.
--
Eric Jain
zenobase.com -- What do you want to track today?
Eric Jain
2014-02-25 05:53:45 UTC
Permalink
Post by dev danke
I think a thread A doing the for-loop test could get suspended at that
point, and then another thread B with a different timestamp value could make
it through the whole for-loop, before the suspended thread A is awoken.
If that happens, the compare-and-set won't do anything, and:

a. If the other thread's timestamp is lower than our timestamp, the
loop test succeeds, so we try again.
b. If the other thread's timestamp is higher than our timestamp, the
loop test fails, so we won't try again.

So where's the problem?
--
Eric Jain
zenobase.com -- What do you want to track today?


------------------------------------

Yahoo Groups Links

<*> To visit your group on the web, go to:
http://groups.yahoo.com/group/seajug/

<*> Your email settings:
Individual Email | Traditional

<*> To change settings online go to:
http://groups.yahoo.com/group/seajug/join
(Yahoo! ID required)

<*> To change settings via email:
seajug-digest-***@public.gmane.org
seajug-fullfeatured-***@public.gmane.org

<*> To unsubscribe from this group, send an email to:
seajug-unsubscribe-***@public.gmane.org

<*> Your use of Yahoo Groups is subject to:
http://info.yahoo.com/legal/us/yahoo/utos/terms/
Douglas Pearson
2014-02-25 06:19:35 UTC
Permalink
This is the code in AtomicLong's getAndSet method:

/**
* Atomically sets to the given value and returns the old value.
*
* @param newValue the new value
* @return the previous value
*/
public final long getAndSet(long newValue) {
while (true) {
long current = get();
if (compareAndSet(current, newValue))
return current;
}
}

which can be adjusted to do the comparison:

public final long setToMaxOfCurrentAndNewValue(long newValue) {
while (true) {
long current = get();

if (current > newValue)
return current ;

// Will only do the set if the atomic value has not changed
// so this only succeeds if 'newValue' is larger than current
atomic value
if (compareAndSet(current, newValue))
return current;
}
}

If you look at all of the "get and do something" methods in AtomicLong they
all look like this.

I think this is functionally equivalent to Eric's code.

Doug
Post by Eric Jain
Post by dev danke
I think a thread A doing the for-loop test could get suspended at that
point, and then another thread B with a different timestamp value could
make
Post by dev danke
it through the whole for-loop, before the suspended thread A is awoken.
a. If the other thread's timestamp is lower than our timestamp, the
loop test succeeds, so we try again.
b. If the other thread's timestamp is higher than our timestamp, the
loop test fails, so we won't try again.
So where's the problem?
--
Eric Jain
zenobase.com -- What do you want to track today?
Dennis Sosnoski
2014-02-25 05:53:42 UTC
Permalink
Yes, Eric's code handles any conditions of this type that I can see. If
the timestamp changes between the for clause and the compareAndSet it'll
just execute the for clause again (until the maximumTimestamp value is
greater than or equal to the value to be set), and the compareAndSet
will fail if there's been any change in the maximumTimestamp value.

Nice way of handling this, Eric. Though if you don't mind assignments
inside a logic expression you can avoid a little redundancy with:

long max;
while ((max = maximumTimestamp.get()) < timestamp &&
!maximumTimestamp.compareAndSet(max, timestamp));

- Dennis
Post by dev danke
Does the for-loop approach guarantee that the same thread doing the
for-loop test "max =
maximumTimestamp.get()" is the same thread calling compareAndSet()?
I think a thread A doing the for-loop test could get suspended at that
point, and then another thread B with a different timestamp value
could make it through the whole for-loop, before the suspended thread
A is awoken.
That doesn't seem thread-safe to me.
Post by dev danke
Eric: In my opinion, your suggestion of using a for-loop does
not prevent a race condition.
How so? We just compare-and-set until the maximum timestamp is equal
to or larger than our timestamp.
--
Eric Jain
zenobase.com <http://zenobase.com> -- What do you want to track today?
Eric Jain
2014-02-25 06:21:16 UTC
Permalink
Post by Dennis Sosnoski
long max;
while ((max = maximumTimestamp.get()) < timestamp &&
!maximumTimestamp.compareAndSet(max, timestamp));
Nice, but this still doesn't fit on one line :-)
--
Eric Jain
zenobase.com -- What do you want to track today?


------------------------------------

Yahoo Groups Links

<*> To visit your group on the web, go to:
http://groups.yahoo.com/group/seajug/

<*> Your email settings:
Individual Email | Traditional

<*> To change settings online go to:
http://groups.yahoo.com/group/seajug/join
(Yahoo! ID required)

<*> To change settings via email:
seajug-digest-***@public.gmane.org
seajug-fullfeatured-***@public.gmane.org

<*> To unsubscribe from this group, send an email to:
seajug-unsubscribe-***@public.gmane.org

<*> Your use of Yahoo Groups is subject to:
http://info.yahoo.com/legal/us/yahoo/utos/terms/
Loading...