Difference between yield() and join() in threads in java?

Multi-threading is very popular topic among interviewers from long time. Though I personally feel that very few of us get real chance to work on a complex multi-threaded application (I got only one chance in last 7 years), still it helps in having the concepts handy to boost your confidence ONLY. Previously, I discussed a similar question about difference between wait() and sleep() method, this time I am discussing difference between join() and yield() methods. Frankly speaking, I have not used any of both methods in practical so please make a argument if you feel otherwise at any point.

Ads by Google

A little background on java thread scheduling

A Java virtual machine is required to implement a preemptive, priority-based scheduler among its various threads. This means that each thread in a Java program is assigned a certain priority, a positive integer that falls within a well-defined range. This priority can be changed by the developer. The Java virtual machine never changes the priority of a thread, even if the thread has been running for a certain period of time.

The priority value is important because the contract between the Java virtual machine and the underlying operating system is that the operating system must generally choose to run the Java thread with the highest priority. That’s what we mean when we say that Java implements a priority-based scheduler. This scheduler is implemented in a preemptive fashion, meaning that when a higher-priority thread comes along, that thread interrupts (preempts) whatever lower-priority thread is running at the time. The contract with the operating system, however, is not absolute, which means that the operating system can sometimes choose to run a lower-priority thread. [I hate this about multi-threading.. nothing is guaranteed :-( ]

Also note that java does not mandate that its threads be time-sliced, but most operating systems do so. There is often some confusion in terminology here: preemption is often confused with time-slicing. In fact, preemption means only that a higher-priority thread runs instead of a lower-priority one, but when threads have the same priority, they do not preempt each other. They are typically subject to time-slicing, but that is not a requirement of Java.

Understanding thread priorities

Understanding the Thread priorities is next important step in learning Multi-threading and specially how yield() works.

  1. Remember that all the threads carry normal priority when a priority is not specified.
  2. Priorities can be specified from 1 to 10. 10 being the highest, 1 being the lowest priority and 5 being the normal priority.
  3. Remember that the thread with highest priority will be given preference in execution. But there is no guarantee that it will be in running state the moment it starts.
  4. Always the currently executing thread might have the higher priority when compared to the threads in the pool who are waiting for their chance.
  5. It is the thread scheduler which decides what thread should be executed.
  6. t.setPriority() can be used to set the priorities for the threads.
  7. Remember that the priorities should be set before the threads start method is invoked.
  8. You can use the constants, MIN_PRIORITY,MAX_PRIORITY and NORM_PRIORITY for setting priorities.

Now when we have some basic understanding of thread scheduling and thread priorities, let’s jump into subject.

yield() method

Theoretically, to ‘yield’ means to let go, to give up, to surrender. A yielding thread tells the virtual machine that it’s willing to let other threads be scheduled in its place. This indicates that it’s not doing something too critical. Note that it’s only a hint, though, and not guaranteed to have any effect at all.

yield() is defined as following in Thread.java.

/**
  *	A hint to the scheduler that the current thread is willing to yield its current use of a processor. The scheduler is free to ignore
  * this hint. Yield is a heuristic attempt to improve relative progression between threads that would otherwise over-utilize a CPU. 
  * Its use should be combined with detailed profiling and benchmarking to ensure that it actually has the desired effect. 
  */

public static native void yield();

Let’s list down important points from above definition:

  • Yield is a Static method and Native too.
  • Yield tells the currently executing thread to give a chance to the threads that have equal priority in the Thread Pool.
  • There is no guarantee that Yield will make the currently executing thread to runnable state immediately.
  • It can only make a thread from Running State to Runnable State, not in wait or blocked state.

yield() method example usage

In below example program, I have created two threads named producer and consumer for no specific reason. Producer is set to minimum priority and consumer is set to maximum priority. I will run below code with/without commenting the line Thread.yield(). Without yield(), though the output changes sometimes, but usually first all consumer lines are printed and then all producer lines.

With using yield() method, both prints one line at a time and pass the chance to another thread, almost all the time.

package test.core.threads;

public class YieldExample
{
   public static void main(String[] args)
   {
      Thread producer = new Producer();
      Thread consumer = new Consumer();
      
      producer.setPriority(Thread.MIN_PRIORITY); //Min Priority
      consumer.setPriority(Thread.MAX_PRIORITY); //Max Priority
      
      producer.start();
      consumer.start();
   }
}

class Producer extends Thread
{
   public void run()
   {
      for (int i = 0; i < 5; i++)
      {
         System.out.println("I am Producer : Produced Item " + i);
         Thread.yield();
      }
   }
}

class Consumer extends Thread
{
   public void run()
   {
      for (int i = 0; i < 5; i++)
      {
         System.out.println("I am Consumer : Consumed Item " + i);
         Thread.yield();
      }
   }
}

Output of above program “without” yield() method

I am Consumer : Consumed Item 0
 I am Consumer : Consumed Item 1
 I am Consumer : Consumed Item 2
 I am Consumer : Consumed Item 3
 I am Consumer : Consumed Item 4
 I am Producer : Produced Item 0
 I am Producer : Produced Item 1
 I am Producer : Produced Item 2
 I am Producer : Produced Item 3
 I am Producer : Produced Item 4

Output of above program “with” yield() method added

I am Producer : Produced Item 0
 I am Consumer : Consumed Item 0
 I am Producer : Produced Item 1
 I am Consumer : Consumed Item 1
 I am Producer : Produced Item 2
 I am Consumer : Consumed Item 2
 I am Producer : Produced Item 3
 I am Consumer : Consumed Item 3
 I am Producer : Produced Item 4
 I am Consumer : Consumed Item 4

join() method

The join() method of a Thread instance can be used to “join” the start of a thread’s execution to the end of another thread’s execution so that a thread will not start running until another thread has ended. If join() is called on a Thread instance, the currently running thread will block until the Thread instance has finished executing.

//Waits for this thread to die. 

public final void join() throws InterruptedException

Giving a timeout within join(), will make the join() effect to be nullified after the specific timeout. When the timeout is reached, the main thread and taskThread are equally probable candidates to execute. However, as with sleep, join is dependent on the OS for timing, so you should not assume that join will wait exactly as long as you specify.

Like sleep, join responds to an interrupt by exiting with an InterruptedException.

join() method example usage

package test.core.threads;

public class JoinExample
{
   public static void main(String[] args) throws InterruptedException
   {
      Thread t = new Thread(new Runnable()
         {
            public void run()
            {
               System.out.println("First task started");
               System.out.println("Sleeping for 2 seconds");
               try
               {
                  Thread.sleep(2000);
               } catch (InterruptedException e)
               {
                  e.printStackTrace();
               }
               System.out.println("First task completed");
            }
         });
      Thread t1 = new Thread(new Runnable()
         {
            public void run()
            {
               System.out.println("Second task completed");
            }
         });
      t.start(); // Line 15
      t.join(); // Line 16
      t1.start();
   }
}

Output:

First task started
Sleeping for 2 seconds
First task completed
Second task completed

That’s all for this quite small but important concept. Let me know of your thoughts in comments section.

Happy Learning !!

Ads by Google

13 thoughts on “Difference between yield() and join() in threads in java?”

  1. Hello Lokesh,

    I am a regular reader of your blogs. Your articles are very comprehensive and easy to learn.

    I was reading this article about Thread.Join(),
    And , i feel the example used here is insufficient to explain Thread.join() and hence is a bit misleading.

    When we use , t.join() , It is always the current thread which is put on waiting state till the tread ‘t’ finishes its processing.
    In the above example , though there are 2 threads created viz -Thread t & Thread t1.
    But when you do t.join() , None of the thread ,t or t1 are “joined” to each other.

    It is the “main” (currently executing) thread which is joined(i.e. waiting) to thread ‘t’ .
    So, main thread halts execution till thread ‘t’ does its Job.

    Hence , there was no use of creating 2 threads , when they are not being “JOINED”.

    I think a modified code could explain things better:

    class JoinExample
    {
    public static void main(String[] args) throws InterruptedException
    {
    Thread t = new Thread(new Runnable()
    {
    public void run()
    {
    System.out.println(“First task started”);
    System.out.println(“Sleeping for 2 seconds”);
    try
    {
    Thread.sleep(2000);
    } catch (InterruptedException e)
    {
    e.printStackTrace();
    }
    System.out.println(“First task completed”);
    }
    });
    t.start(); // Line 15
    t.join(); // Line 16
    System.out.println(“Main finished”);
    }
    }

  2. The thread priorities ranges varies from operating system to operating system. For windows it is 1-10, linux 1-5 and for solaris 1-127. Java API suggests use to use the constants MIN_PRIORITY and MAX_PRIORITY instead of directly providing the direct priority numbers.

  3. Following statement is misleading.
    “Without yield(), though the output changes sometimes, but usually first all prouder lines are printed and then all consumer lines.”

    It’s the other way my friend. Consumers are printed first and then producers as Consumers are having highest priority.

  4. Hey Lokesh I m getting some weired output as shown below :

    Producing 0
    Consuming 0
    Consuming 1
    Consuming 2
    Consuming 3
    Producing 1
    Producing 2
    Producing 3

    1. No output should be considered as weird. In multi-threading, you can only ask the processor to give up a thread and execute other, you can’t force it.

  5. I tried the YieldExample many times on my laptop using “1.6.0_45″, I found the result is very randomly and it is almost not relevant to the yield statement

    1. In multi-threading programs, results always vary so without yield() it’s quite expected. After using yield(), there must be some fixed ordering. Can you please post here, your outputs.

Note:- In comment box, please put your code inside [java] ... [/java] OR [xml] ... [/xml] tags otherwise it may not appear as intended.

Leave a Reply

Your email address will not be published. Required fields are marked *


7 − one =

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>