Hendrik
Hendrik

Reputation: 151

How to get threads with loops running concurrently to work with Thread.yield()?

I have the following situation. I have an application that runs mostly on one thread. It has grown large, so I would like to run a watchdog thread that gets called whenever the main thread changes into a different block of code / method / class so I can see there is "movement" in the code. If the watchdog gets called by the same area for more than a second or a few, it shall set a volatile boolean that the main thread reads at the next checkpoint and terminate / restart. Now the problem is getting either of the threads to run somewhat at the same time. As soon as the main thread is running, it will not let the watchdog timer count properly. I was therefore thinking of yielding every time it calls the watchdog (so it could calculate time passed and set the value) but to no avail. Using Thread.sleep(1) instead of Thread.yield() works. But I don't want to have several areas of code just wasting calculation time, I am sure I am not doing it the way it is meant to be used.

Here a very simple example of how I would use Thread.yield(). I do not understand why the Threads here will not switch (they do, after a "long" and largely unpredictable time). Please give me an advice on how to make this simple example output ONE and TWO after each other. Like written before, if I switch yield() with sleep(1), it will work just like I'd need it to (in spite of waiting senselessly).

    Runnable run1 = new Runnable(){
        public void run(){
            while(true){
                System.out.println("ONE");
                Thread.yield();
            }
        }
    };

    Runnable run2 = new Runnable(){
        public void run(){
            while(true){
                System.out.println("TWO");
                Thread.yield();
            }
        }
    };

    Thread tr1 = new Thread(run1);              
    Thread tr2 = new Thread(run2);

    tr1.start();
    tr2.start();

Upvotes: 4

Views: 1105

Answers (2)

Gray
Gray

Reputation: 116888

I do not understand why the Threads here will not switch (they do, after a "long" and largely unpredictable time). Please give me an advice on how to make this simple example output ONE and TWO after each other. Like written before, if I switch yield() with sleep(1), it will work just like I'd need it to (in spite of waiting senselessly).

I think this is more about the difference between ~1000 println calls in a second (when you use sleep(1)) and many, many more without the sleep. I think the Thread is actually yielding but it may be that it is on a multiple processor box so the yield is effectively a no-op.

So what you are seeing is purely a race condition high volume blast to System.out. If you ran this for a minute with the results going to a file I think you'd see a similar number of "ONE" and "TWO" messages in the output. Even if you removed the yield() you would see this behavior.

I just ran a quick trial with your code sending the output to /tmp/x. The program with yield() ran for 5 seconds, generated 1.9m/483k lines, with the output sort | uniq -c of:

243152 ONE
240409 TWO

This means that each thread is generating upwards of 40,000 lines/second. Then I removed the yield() statements and I got just about the same results with different counts of lines like you'd expect with the race conditions -- but the same order of magnitude.

Upvotes: 0

user177800
user177800

Reputation:

Thread.yield()

This static method is essentially used to notify the system that the current thread is willing to "give up the CPU" for a while. The general idea is that:

The thread scheduler will select a different thread to run instead of the current one.

However, the details of how yielding is implemented by the thread scheduler differ from platform to platform. In general, you shouldn't rely on it behaving in a particular way. Things that differ include:

when, after yielding, the thread will get an opportunity to run again; whether or not the thread foregoes its remaining quantum.

The take away is this behavior is pretty much optional and not guaranteed to actually do anything deterministically.

What you are trying to do is serialize the output of two threads in your example and synchronize the output in your stated problem ( which is a different problem ), and that will require some sort of lock or mutex to block the second thread until the first thread is done, which kind of defeats the point of concurrency which is usually the reason threads are used.

Solution

What you really want is a shared piece of data for a flag status that the second thread can react to the first thread changing. Preferably and event driven message passing pattern would be even easier to implement in a concurrently safe manner.

The second thread would be spawned by the first thread and a method called on it to increment the counter for which block it is in, you would just use pure message passing and pass in a state flag Enum or some other notification of a state change.

What you don't want to do is do any kind of polling. Make it event driven and just have the second thread running always and checking the state of its instance variable that gets set by the parent thread.

Upvotes: 10

Related Questions