How to make threads with loops work simultaneously with Thread.yield ()?

I have the following situation. I have an application that runs mostly on a single thread. It has become big, so I would like to start the watchdog thread, which is called every time the main thread changes to another block of code / method / class, so I see that there is “movement” in the code. If the watchdog timer is called by one area for more than one second or several, it must set a volatile boolean, which the main thread reads at the next breakpoint and terminates / restarts. Now the problem is that one of the threads starts at the same time. Once the main thread is started, it will not allow the correct watchdog timer count. So I thought about yielding every time he calls a watchdog timer (so that he can calculate the time and set the value), but to no avail. Using Thread.sleep (1) instead of Thread.yield () works. But I don’t want several areas of the code to simply waste computation time, I’m sure that I don’t do it the way it is intended to be used.

Here is a very simple example of how I will use Thread.yield (). I don’t understand why the threads here will not switch (they do, after a "long" and largely unpredictable time). Please give me advice on how to make this simple example of outputting ONE and TWO after each other. As before, if I switch yield () with sleep (1), it will work just as I need (despite the wait is pointless).

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(); 
+4
source share
2 answers

I don’t understand why the threads here will not switch (they do, after a "long" and largely unpredictable time). Please give me advice on how to make this simple example of outputting ONE and TWO after each other. As before, if I switch yield () with sleep (1), it will work just as I need (despite the wait is pointless).

I think this is more due to the difference between ~ 1000 println calls per second (when using sleep(1) ) and many, and even more without sleep. I think that Thread is actually inferior, but it may be that it is on a multiprocessor box, so the yield does not actually work.

So, what you see is just the explosion of a large volume race on System.out . If you run this for a minute with the results going to a file, I think you will see a similar number of "ONE" and "TWO" messages in the output. Even if you removed yield() , you will see this behavior.

I just checked out a quick trial with code sending the output to /tmp/x . The program with yield() executed within 5 seconds, generated lines of 1.9 m / 483 thousand, With the output sort | uniq -c sort | uniq -c from:

 243152 ONE 240409 TWO 

This means that each stream generates more than 40,000 lines per second. Then I deleted the yield() , and I got roughly the same results with different row values, as you would expect under race conditions, but with the same order of magnitude.

0
source

Thread.yield ()

This static method is mainly used to notify the system that the current thread is ready to "abandon the processor" 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 profitability is realized by the flow planner differs from platform to platform. In general, you should not rely on the fact that he behaves in a certain way. The differences include:

when, after the assignment, the thread will be able to start again; regardless of whether the thread matches its remaining quantum.

The refusal is that this behavior is largely optional, and something deterministic is not really guaranteed.

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

Decision

What you really need is a common piece of data for the flag status, which the second thread can respond to the first thread. Preferably, an event-driven message passing pattern will be even simpler to implement at the same time in a secure manner.

The second thread will be spawned by the first thread and the method it calls to increase the counter for which it is located, you simply use a clean message transfer and pass the Enum status flag or other status change notification.

What you do not want to do is do any polls. Make it event driven and just execute the second thread, always checking the state of its instance variable, which is set by the parent thread.

+10
source

Source: https://habr.com/ru/post/1400259/