Java Concurrency – Difference between yield() and join()

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.

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 !!

Was this post helpful?

Join 7000+ Fellow Programmers

Subscribe to get new post notifications, industry updates, best practices, and much more. Directly into your inbox, for free.

31 thoughts on “Java Concurrency – Difference between yield() and join()”

  1. Hey buddy. Pretty great explanation and the insights into the significance of each topic is exceptional.
    One suggestion though, please try to keep an order of the posts for the tutorials. There seems to be a zig zag manner. Or am I missing the track somewhere?

    Thanks in advance. Keep Rocking…!!!

    • Thanks for the feedback. Originally these posts were written randomly. I tried to add some sequence later. Still lots of things are left and I am working on them.

  2. Your way of explanation need to improve more. Now it will understood for only those who has some knowledge. it will not understand by freshers and beginners.
    Need to improve a lot in explanation

  3. Hi Lokesh,
    Just to add one imp point. If join() is called on a dead thread or thread which is not yet started than the control immediately return back without waiting.

    Regards,
    Himansu

  4. You are saying that Yield method let other waiting threads to execute but if they are of same priority. In your example the producer and consumer are apparently of totally different priority.
    How is yield affecting their execution order??

      • Your reply is not clear. Are saying the yield only works for thread pool or the priority condition is associated with thread pool only?
        It’ll be better if you could please explain it in detail for all of the readers.
        Thanks!!

        • Yes Harsh, In thread-pool, yield() will try to suspend currently executing thread, and JVM will first try to choose a thread with equal priority inside pool, if none is found – it may choose the original thread or may choose any other thread of unequal priority.
          Again, It is on best effort basis. This execution order is not guaranteed as most of the cases of the cases in multi-threading.

          Yield method only suggest that current thread is ready to give up resources if some other thread want to take over. But JVM may choose to select that very thread everytime, irrespective of all reasoning. No guarantee at all.

  5. We have only runnable state which is running state. But line states they are two different.. Please clarify.
    •It can only make a thread from Running State to Runnable State, not in wait or blocked state.

    • The thread is in runnable state after invocation of start() method, but the thread scheduler has not selected it to be the running thread. The thread is in running state if the thread scheduler has selected it. The thread is in running state if the thread scheduler has selected it.

  6. HI lokesh,
    Regarding join() method. Its written that “If join() is called on a Thread instance, the currently running thread will block until the Thread instance has finished executing”. Can you please explain this line in more detail whenever you get time 🙂 . I am confused in the line “The currently running thread will block”.
    As far as I understand its :
    t.start();
    t.join();
    t1.start();
    In the above case thread t will finish first then t1 will start.

    If I write :
    t.start();
    t1.start();
    t.join();
    Both will be started and t.join() has no impact.

    Is that mean that we have to call join on thread object just after calling start() method so that no other thread will start executing until our joined thread exits.
    I know its a small doubt 🙂 . please explain . Thanks in advance

  7. Hi Lokesh,
    I am getting the following output without yield :
    I am Consumer : Consumed Item 0
    I am Producer : Produced Item 0
    I am Consumer : Consumed Item 1
    I am Producer : Produced Item 1
    I am Consumer : Consumed Item 2
    I am Producer : Produced Item 2
    I am Consumer : Consumed Item 3
    I am Producer : Produced Item 3
    I am Consumer : Consumed Item 4
    I am Producer : Produced Item 4

    and with yield() the output is :
    I am Producer : Produced Item 0
    I am Consumer : Consumed Item 0
    I am Consumer : Consumed Item 1
    I am Producer : Produced Item 1
    I am Producer : Produced Item 2
    I am Producer : Produced Item 3
    I am Producer : Produced Item 4
    I am Consumer : Consumed Item 2
    I am Consumer : Consumed Item 3
    I am Consumer : Consumed Item 4

    I agree that in threading we can’t force the processor we only give request. But Why the output is opposite ??

    • Again OS plays a vital role in this. Even though you called producer.start() OS will register that to its thread scheduler. It will run from that. We cant predict which will execute first.

    • Producer should have high priority than consumer. Change the priority you will get expected output.

  8. 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”);
    }
    }

  9. 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.

  10. 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.

  11. 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

    • 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.

  12. 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

Comments are closed.

HowToDoInJava

A blog about Java and its related technologies, the best practices, algorithms, interview questions, scripting languages, and Python.