15

While working on my Java application, I've a simple multithreading case (one asynchronous resource loader thread and one main thread waiting for the loader to finish, updating the UI with the progress), which I figured to solve by calling

while( !foo.isInitialized() ) {
     Thread.yield();
}

in the main thread. I'm aware that there are more robust solutions; still, the loader is not designed by me and it's a basically read-only library (I can't simply wait(), because I can't make it send me a notify(); also, it doesn't die after finishing), and I just need to wait until the loading is done.

Java doc says that (note this was not present in 1.6 docs and was added by 1.7 docs)

It is rarely appropriate to use this method.

NetBeans warns me that

Invocation of method yield() on java.lang.Thread is usually used to masquerade synchronization problems and should be avoided.

Google Codepro AnalytiX, OTOH, says

The method Thread.yield() should not be used because its behavior is not consistent across all platforms.

Should I be concerned with those warnings and try to find a better solution (all suggestions are welcome), or should I consider those as "warning noise" and suppress/ignore them?

Note: I thought about the obvious possibility of using sleep() (Are Thread.sleep(0) and Thread.yield() statements equivalent? is worth mentioning here); still, if yielding has no "bonus" over constantly sleeping, why does Java provide it at all - and what are the actual valid use cases for it then?

Slightly related: Is there a better solution to Thread.yield()? & Thread.Sleep or Thread.Yield

Community
  • 1
  • 1
  • Very harmful. What if there's no other ready-to-run thread to yield to? If you want to wait for something, *wait* for it. – David Schwartz Jun 23 '15 at 19:11
  • 1
    @DavidSchwartz It will simply be ignored by the thread scheduler. – Mordechai Jun 23 '15 at 19:13
  • Yes you should be concerned. Can you explain more what you are trying to actually accomplish? What is your goal here? – markspace Jun 23 '15 at 19:14
  • 2
    See also: http://stackoverflow.com/questions/27516719/java-wait-for-third-party-threads-to-finish – assylias Jun 23 '15 at 19:15
  • 1
    @markspace Think of _wait_ -ing the thread with a `while` loop. The call `Thread.yield` should just flag the system thread scheduler to lower this threads priority for a moment. – Mordechai Jun 23 '15 at 19:16
  • 1
    My question was to the OP. What is he actually doing here? There has to be a better way to wait. So I'm trying to dig for more information about the library/loader he's using. – markspace Jun 23 '15 at 19:18
  • @markspace the loader is a black box, with the only multitasking entry point being the `isInitialized()` method –  Jun 23 '15 at 19:19
  • Please explain more about the scenario. Is your loader a `Runnable` or a `Thread` subclass? Does it finish running when done? You might be able to `join()` it or use an Executor to wrap it in a `Future`, but we'll need more information to put you in the right direction. A bit more code would go a long way. – RealSkeptic Jun 23 '15 at 19:26
  • @RealSkeptic it's a Thread wrapping native code execution. It doesn't die when done. It just starts to return `true` from `isInitialized()` method. –  Jun 23 '15 at 19:29
  • Are you sure that this means it doesn't die? Does `foo.isAlive()` return `true` after `isInitialized()` returns `true`? – RealSkeptic Jun 23 '15 at 19:31
  • Yup, I'm sure it doesn't die. It's active the whole time, waiting for more resources to load; then it starts returning `false` from `isInitialized()` again, until it loads everything rescheduled. It dies with the whole application. –  Jun 23 '15 at 19:33
  • @MouseEvent When you say "it will simply be ignored", what's the "it" you are referring to? If you mean the attempt to yield will be ignored, then that's a huge problem. (For example, consider if a thread is trying to get useful work done in another virtual core that shares this physical core.) – David Schwartz Jun 23 '15 at 19:39
  • @DavidSchwartz In theory, you're right. I just responded to your question. – Mordechai Jun 23 '15 at 19:40
  • @MouseEvent Make up your mind.*Either* 'it will simply be ignored' *or* it will 'just flag the system thread scheduler to lower this thread's priority for a moment'. You can't have it both ways. – user207421 Jun 23 '15 at 20:02
  • 1
    @EJP mind reading the [JavaDoc](http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#yield()). – Mordechai Jun 23 '15 at 20:04

1 Answers1

4

The main problem with calling Thread.yield() in a while loop without any wait mechanics is that it easily becomes a busy-wait loop using 100% of one of your cores.

If there are no other threads to schedule when you yield, the yielded thread will probably be re-scheduled very quickly and hence resulting in high CPU utilization.

Other than that, in this case, I can't see it would be more harmful than that. However, it is pretty pointless - if you are going to write a busy-wait loop you could just do while (!foo.isInitialized()); and avoid stressing the scheduler.

What you should do, if you cannot have a notify mechanism, is to at least sleep in the loop. This will allow your CPUs to rest a bit.

Typical implementation of such a loop:

while(!foo.isInitialized()) { 
    try {
        Thread.sleep(20);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        return; // or handle some other way
    }
}
K Erlandsson
  • 13,408
  • 6
  • 51
  • 67
  • Depending on how critical this code is, it can be much more harmful than that. If this code doesn't matter much, then it's not going to matter much. But if it does, you can cause serious performance problems. For example, suppose the thread we're waiting for is running in a virtual core that shares this physical core. And consider what happens when we finally exit this loop and the branch is mispredicted. This basically does everything wrong. – David Schwartz Jun 23 '15 at 19:41
  • @DavidSchwartz With "more harmful than that" - i was relating to regular busy-wait loop. I'm not fully understanding your comment. Do you mean that calling `Thread.yield()` is much worse than an ordinary busy-wait in your scenario? If so, could you explain it a bit more, I would love to understand better! – K Erlandsson Jun 23 '15 at 19:45
  • It could be more harmful than a regular busy-wait loop because the invocation of the scheduler can cause more performance impact than just a tight spin loop (by causing cache invalidations on other cores, for example). But I interpreted "I can't see it would be more harmful than that" to mean that you didn't envision any harms other than the ones you described. (There's no evidence the OP understands what harm a busy wait loop will do.) – David Schwartz Jun 23 '15 at 20:36