What are the main uses of yield(), and how does it differ from join() and interrupt()?

divz picture divz · Aug 8, 2011 · Viewed 98.6k times · Source

I am a little bit confused about the use of yield() method in Java, specifically in the example code below. I've also read that yield() is 'used to prevent execution of a thread'.

My questions are:

  1. I believe the code below result in the same output both when using yield() and when not using it. Is this correct?

  2. What are, in fact, the main uses of yield()?

  3. In what ways is yield() different from the join() and interrupt() methods?

The code example:

public class MyRunnable implements Runnable {

   public static void main(String[] args) {
      Thread t = new Thread(new MyRunnable());
      t.start();

      for(int i=0; i<5; i++) {
          System.out.println("Inside main");
      }
   }

   public void run() {
      for(int i=0; i<5; i++) {
          System.out.println("Inside run");
          Thread.yield();
      }
   }
}

I obtain the same output using the code above both with and without using yield():

Inside main
Inside main
Inside main
Inside main
Inside main
Inside run
Inside run
Inside run
Inside run
Inside run

Answer

Sathwick picture Sathwick · Aug 8, 2011

Source: http://www.javamex.com/tutorials/threads/yield.shtml

Windows

In the Hotspot implementation, the way that Thread.yield() works has changed between Java 5 and Java 6.

In Java 5, Thread.yield() calls the Windows API call Sleep(0). This has the special effect of clearing the current thread's quantum and putting it to the end of the queue for its priority level. In other words, all runnable threads of the same priority (and those of greater priority) will get a chance to run before the yielded thread is next given CPU time. When it is eventually re-scheduled, it will come back with a full full quantum, but doesn't "carry over" any of the remaining quantum from the time of yielding. This behaviour is a little different from a non-zero sleep where the sleeping thread generally loses 1 quantum value (in effect, 1/3 of a 10 or 15ms tick).

In Java 6, this behaviour was changed. The Hotspot VM now implements Thread.yield() using the Windows SwitchToThread() API call. This call makes the current thread give up its current timeslice, but not its entire quantum. This means that depending on the priorities of other threads, the yielding thread can be scheduled back in one interrupt period later. (See the section on thread scheduling for more information on timeslices.)

Linux

Under Linux, Hotspot simply calls sched_yield(). The consequences of this call are a little different, and possibly more severe than under Windows:

  • a yielded thread will not get another slice of CPU until all other threads have had a slice of CPU;
  • (at least in kernel 2.6.8 onwards), the fact that the thread has yielded is implicitly taken into account by the scheduler's heuristics on its recent CPU allocation— thus, implicitly, a thread that has yielded could be given more CPU when scheduled in the future.

(See the section on thread scheduling for more details on priorities and scheduling algorithms.)

When to use yield()?

I would say practically never. Its behaviour isn't standardly defined and there are generally better ways to perform the tasks that you might want to perform with yield():

  • if you're trying to use only a portion of the CPU, you can do this in a more controllable way by estimating how much CPU the thread has used in its last chunk of processing, then sleeping for some amount of time to compensate: see the sleep() method;
  • if you're waiting for a process or resource to complete or become available, there are more efficient ways to accomplish this, such as by using join() to wait for another thread to complete, using the wait/notify mechanism to allow one thread to signal to another that a task is complete, or ideally by using one of the Java 5 concurrency constructs such as a Semaphore or blocking queue.