2

I found a piece of code where the thread seems to starve. Below is a simplified example. Is this an example for starvation? What is the reason why the thread does not terminate?

Note: Changing the sleep to 1 will sometimes result in termination. The commented out Thread.yield() would solve the problem (for me).

public class Foo {

    public static boolean finished = false;

    public static void main(String[] args) {

          Runnable worker = new Runnable() {

                 @Override
                 public void run() {

                      try {
                           Thread.sleep(10);
                      } catch (InterruptedException e) {
                          // TODO Auto-generated catch block
                          e.printStackTrace();
                      }

                      finished = true;
                 }
            };

            new Thread(worker).start();

            while (!finished) {
//          Thread.yield();
        }
    }
}

2 Answers2

8

You probably need to get informed on the Java Memory Model. Multithreading isn't just about interleaving the actions of threads; it is about the visibility of actions by one thread to another.

At the bottom of this issue lies the need for aggressive optimization in the face of concurrency: any mechanism which ensures memory coherency between threads is expensive, and much (most) of the data is not shared between threads. Therefore the data not explicitly marked volatile, or protected by locks, is treated as thread-local by default (without strict guarantees, of course).

In your case, finished is such a variable which is allowed to be treated as thread-local if it pleases the runtime. It does please it because the

while (!finished);

loop can be rewritten to just

if (!finished) while (true);

If you did any important work inside the loop, it would perform a bit better because the read of finished wouldn't be needlessly repeated, thus possibly destroying one whole CPU cache line.

The above discussion should be enough to answer your immediate question, "is this starvation": the reason the loop doesn't finish is not starvation, but the inability to see the write by the other thread.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • Thanks for the useful answer! What really puzzled me was that the thread almost always terminated when it contained only a few inexpensive statements (similar to a Thread.sleep(1)). The problem showed up, when I added further code which is simulated by the Thread.sleep(100) above ... – user3220859 Jan 21 '14 at 21:13
  • If you're still wondering why that is, the reason is that it takes some time before the infinite loop in `main` is JIT-compiled into the optimized version which contains the "loop hoisting" optimization. Only after that optimized version runs for the first time will the code enter the infinite loop which does no further checking of the flag. – Marko Topolnik Jan 21 '14 at 22:08
0

There's no starvation here, because you're not doing any work. Starvation means various threads are trying to access the same, limited set of resources. What are the resources each thread is trying to access here? They're not "eating" anything, so they can't starve.

yshavit
  • 42,327
  • 7
  • 87
  • 124