• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • Ron McLeod
  • paul wheaton
  • Jeanne Boyarsky
Sheriffs:
  • Paul Clapham
  • Devaka Cooray
Saloon Keepers:
  • Tim Holloway
  • Roland Mueller
  • Himai Minh
Bartenders:

Do the concurrent classes provide a higher level API for threads to try again until they complete?

 
Ranch Hand
Posts: 684
3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Before the concurrent classes, we had wait, notify, notifyAll and looping and sleeping outside a synchronized block.
I was wondering, with all the (new to me) convenience classes, how come there isn't the equivalent of the above?
I am missing something but I do not see a higher level API for threads to try again until they complete.

For instance, this code from Boyarsky-Selikoff does not print "Tie!" 10 times.

So I tried to modify it and all I could come up with was this ugly code which does print "Tie!" ten times.
I was wondering if there was a better way.


 
Marshal
Posts: 80741
485
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Anil Philip wrote:. . . how come there isn't the equivalent of the above? . . .

But there is; look for Condition#await(), and signal() and signalAll(), etc.
 
Author
Posts: 311
13
Scala IntelliJ IDE Netbeans IDE Python Java Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Anil Philip wrote:Before the concurrent classes, we had wait, notify, notifyAll and looping and sleeping outside a synchronized block.
I was wondering, with all the (new to me) convenience classes, how come there isn't the equivalent of the above?



Because "busy waiting" is a bad way to do it. Always was, still is

You should not use wait/notify etc inside loops and sleeps, and you shouldn't use the newer library features that way either. The point of notify (and the "signal", and "await" and related library features) is that your thread does *nothing* until the situation that it's waiting for has been made to be true. It's the thread that changes the situation to be the situation your thread is waiting for that triggers the OS to restart your thread.

Sometimes you have to "poll" or "busy wait", usually because of a bad existing design that's too hard to change. But generally that's like the kids in the back seat of the car asking "are we there yet" every few minutes on an hours-long car journey.

Busy waiting slows your response, because you only check now and again, and it wastes CPU power, because you have to check.

And, the two work against each other: faster polling shortens the response latency, but increases CPU wastage. Slower polling, vice versa.

All that said, the JVM *does* busy wait somewhat, but it's a behavior that's carefully optimized in relation to the expense of cache invalidation in context switches that might "switch back" very soon, and way beyond what's sensible to discuss in this thread
 
Master Rancher
Posts: 5170
83
  • Likes 2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Simon++

Incidentally, in TieShoes2 by adding the synchronized(this) part, you've introduced an alternate exclusion mechanism that really makes the ReentrantLock completely unnecessary - your tryLock() calls will always succeed, because you only make them when you have already acquired the sync lock on this.  In your example there is only one TieShoes2 instance, and one Lock instance to go with it (the field "shoes") - the only time the lock is tryLocked is when you've already ensured no other thread is accessing it.  So there's no longer any point to having the Lock, and no danger of your tryLock() not working, so no need to retry.

In general, you don't want to mix using synchronized and using java.util.concurrent.Lock objects.  They do similar things, and it's simpler to use one or the other, not both.  Typically synchronized is simpler to use, while java.util.concurrent.Lock is more flexible and powerful.

This example is extremely contrived, so it's hard to really tell what the point was.  In more realistic situations like "keep trying until you get a connection, or until it's failed ten times, with 60 second timeouts" or whatever... for stuff like that, you might want to check out the Resilience4J library.  E.g. the Retry module.
 
Bartender
Posts: 15741
368
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Simon Roberts wrote:You should not use wait/notify etc inside loops and sleeps, and you shouldn't use the newer library features that way either


That's not exactly true.

You were always supposed to call wait() inside a loop that checks the waiting condition. That's because wait() can unblock spuriously without a notify() being called.

The same is true for Condition.await(). It's not considered a busy wait, because even when spurious wake-ups happen, most of the time the thread is still blocked in the wait() call.

ReentrantLock is pretty much a direct replacement for the synchronized keyword. Its benefit is that it promotes a more object oriented approach to acquiring object monitors, and it allows you to create fine-tuned waiting conditions.
 
Mike Simmons
Master Rancher
Posts: 5170
83
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
True.  I agree with Simon's admonishment not to do a loop with sleep inside a loop.  Or even worse, don't do a loop with no sleep or wait, busily checking some condition as often as possible.  But a wait should certainly be inside a loop to check the condition.  I didn't notice that Simon's phrasing was preventing that option.
 
Simon Roberts
Author
Posts: 311
13
Scala IntelliJ IDE Netbeans IDE Python Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:
That's not exactly true.

You were always supposed to call wait() inside a loop that checks the waiting condition. That's because wait() can unblock spuriously without a notify() being called.



Correct, but not in the sense of "busy waiting", sheesh, it's impossible to get every detail into a post, sigh. But you're right to call out the ambiguity/incompleteness in my comment.

The *expectation*, the "general plan" if you will, is that when wait, await, and the like bring a thread to back to runnable, you're ready to go and your condition "should" be set up. But that can't be guaranteed, so you must test again and be willing to wait again.

Notice the structure "while (!gotLock ... ) sleep(100)

That's the problem part of the original comment, and the part at which my remark was addressed. That is the repetitive "are we there yet" known as "busy waiting" and should *not* be done. I.e. don't keep waking up on a timeout to see if a buffer is full or a condition flag has changed, or whatever.

And, mixing synchronized with the lock acquisition is undesirable too.

The proper approach to Anil's situation is to replace that entire synchronized, while not gotlock tihing, with a simple, blocking call to lock.

Also, "unlock" should be in a finally block, while the lock comes right before a try block.

If nobody beats me to it, I'll try to rewrite the code to "do it right" but I'm a bit busy right now, so if anyone else wants to volunteer, go right ahead!
 
Simon Roberts
Author
Posts: 311
13
Scala IntelliJ IDE Netbeans IDE Python Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well, I guess I couldn't leave it alone. Here's what I believe you're trying to get at Anil. If not, perhaps you'd explain what this doesn't do. Notice, no sleep, no polling the lock. You just block until you win the lock, then do what you need. And notice how much faster this is (because it doesn't have to wait 100 milliseconds between "attempts", it just does what it needs to and doesn't run when it can't do it:




 
Anil Philip
Ranch Hand
Posts: 684
3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thank you!
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
reply
    Bookmark Topic Watch Topic
  • New Topic