Jim
Jim

Reputation: 19582

How does yield work here?

The method Thread.yield:

Causes the currently executing thread object to temporarily pause and allow other threads to execute.

So in the following code:

public class Test implements Runnable {  

    private int stopValue;  

    public Fib(int stopValue){  
        this.stopValue = stopValue;  
    }  

    @Override  
    public void run() {  

        System.out.println("In test thread");  
        for(int i = 0; i < stopValue; i++){  
            c = i + 1;  
        }  

        System.out.println("Result = "+c);        
    }  

    public static void main(String[] args){  
        int defaultStop = 1024;  
        if(args.length > 0){   
            defaultStop = Integer.parseInt(args[0]);  
        }  
        Thread a = new Thread(new Fib(defaultStop));  
        System.out.println("In main");  
        a.setDaemon(true);  
        a.start();  
        Thread.yield();       
        System.out.println("Back in main");  
    }  

}

I expect that I should see:

  1. In main then
  2. In test thread

and the rest would be undefined. But I don't understand why sometimes I only see: In main and Back in main and not any print statement from Test thread?

Upvotes: 1

Views: 307

Answers (5)

Gray
Gray

Reputation: 116888

@Peter's answer is a good one but I wanted to add some additional information as an answer.

First, as mentioned elsewhere, the a.setDaemon(true) causes the JVM to not wait for the Thread a to finish before quitting. If your real question is how to make sure that the Thread a does it's work before the JVM shuts down then removing the setDaemon(true) may be the solution. Daemon threads can be killed when the JVM exits. Non-daemon threads will be waited for. So the main() method might return and the main thread might exit but your Thread a would still run to completion.

In terms of Thread.yield(), as you mention, the javadocs state:

Causes the currently executing thread object to temporarily pause and allow other threads to execute.

This, however, is somewhat misleading. For example, if you have 2 threads running and 2 or more processors on your architecture, then the yield() will effectively be a no-op. There are no other threads in the run queue that are waiting for processor resources so the main thread would be quickly rescheduled and would continue running with minimal pause.

Even if your are running on a single CPU system and your Main does yield(), your Thread a goes to do a System.out which is IO. The IO may block causing thread execution to switch back to Main immediately.

When it comes down to it, only in very unique circumstances is a use of yield() necessary. I've done a lot of multithreading programming and I've never used it. Trusting that the JVM thread scheduling will "do the right thing" in terms of time slicing is always recommended unless you have profiler output or expert advice to the contrary.

Upvotes: 0

Peter Lawrey
Peter Lawrey

Reputation: 533570

yield() is a hint to the OS scheduled but doesn't provide any guarantees in terms of scheduling. It doesn't always pause very long. If you call it repeatly it might only take a few micro-seconds.

Starting a thread takes time and even if you main thread pauses briefly, it may finish before the background thread starts.


As you can see, yield() pauses very briefly.

long start = System.nanoTime();
long runs = 20000000;
for (int i = 0; i < runs; i++)
    Thread.yield();
long time = System.nanoTime() - start;
System.out.printf("Thread.yield() took an average of %,d ns.%n", time / runs);

prints

Thread.yield() took an average of 148 ns.

by comparison, System.nanoTime take longer on my machine.

long start = System.nanoTime();
long runs = 20000000;
for (int i = 0; i < runs; i++)
    System.nanoTime();
long time = System.nanoTime() - start;
System.out.printf("System.nanoTime() took an average of %,d ns.%n", time / runs);

prints

System.nanoTime() took an average of 656 ns.

Both times will vary from OS to OS and machine to machine.

Upvotes: 4

code phreak
code phreak

Reputation: 43

Try replacing your Thread.yield() with:

try {
        Thread.sleep(500);
    } catch (InterruptedException ex) {
        System.out.println(ex);
    }

Upvotes: 0

Martin James
Martin James

Reputation: 24867

Well, the yield() probably does nothing at all because the set of ready threads is less than the number of cores, in which case both threads can run anyway and main() will just continue to run on to the core it was running while the OS issues, (quite likely queues), a call to its intercore driver to run the new thread on another CPU core. Then there's the interaction with 'System.out.println' - an output stream call that is probably protected with a mutex.

I cannot quickly find any understandable explanation of what yield() actually does in differing environments/CPU/OS - one of the reasons I have never used it. The other is that I can't think of any use for it no matter how it works.

Upvotes: 2

Francis Upton IV
Francis Upton IV

Reputation: 19443

The main process might have exited before the thread got a chance to start. There is no guarantee that Thread.yield() will force the thread to run in any particular time. If the thread did not start, then the setDaemon() would have no effect.

Upvotes: 0

Related Questions