yield ()의 주요 용도는 무엇이며 join () 및 interrupt ()와 어떻게 다릅니 까?
yield()
특히 아래 예제 코드에서 Java 의 메서드 사용에 대해 약간 혼란스러워 합니다. 또한 yield ()는 '스레드 실행을 방지하는 데 사용됨'을 읽었습니다.
내 질문은 다음과 같습니다.
아래 코드는 사용할 때
yield()
와 사용하지 않을 때 모두 동일한 결과를 산출한다고 생각합니다 . 이 올바른지?실제로의 주요 용도는
yield()
무엇입니까?및 방법 과
yield()
다른 점은 무엇 입니까?join()
interrupt()
코드 예 :
public class MyRunnable implements Runnable {
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable());
t.start();
for(int i=0; i<5; i++) {
System.out.println("Inside main");
}
}
public void run() {
for(int i=0; i<5; i++) {
System.out.println("Inside run");
Thread.yield();
}
}
}
위의 코드를 사용하거나 사용하지 않고 동일한 출력을 얻습니다 yield()
.
Inside main
Inside main
Inside main
Inside main
Inside main
Inside run
Inside run
Inside run
Inside run
Inside run
출처 : http://www.javamex.com/tutorials/threads/yield.shtml
윈도우
핫스팟 구현에서
Thread.yield()
작동 방식은 Java 5와 Java 6간에 변경되었습니다.Java 5
Thread.yield()
에서 Windows API 호출을 호출Sleep(0)
합니다. 이것은 현재 스레드의 퀀텀 을 지우고 우선 순위 수준 에 대해 큐 의 끝에 넣는 특수 효과가 있습니다 . 즉, 동일한 우선 순위 (및 더 높은 우선 순위의 스레드)의 모든 실행 가능한 스레드는 양보 된 스레드가 다음에 CPU 시간이 주어지기 전에 실행될 기회를 갖게됩니다. 결국 일정이 다시 잡히면 완전한 전체 퀀텀으로 돌아 오지만 양보 시점부터 남은 퀀텀을 "이월"하지는 않습니다. 이 동작은 수면 스레드가 일반적으로 1 개의 양자 값 (실제로는 10 또는 15ms 틱의 1/3)을 잃는 0이 아닌 수면과는 약간 다릅니다.Java 6에서는이 동작이 변경되었습니다. Hotspot VM은 이제
Thread.yield()
WindowsSwitchToThread()
API 호출을 사용하여 구현 됩니다 . 이 호출은 현재 스레드 가 전체 퀀텀이 아닌 현재 타임 슬라이스를 포기하도록합니다 . 이는 다른 스레드의 우선 순위에 따라 양보 스레드가 나중에 한 인터럽트 기간으로 다시 예약 될 수 있음을 의미합니다 . ( 타임 슬라이스에 대한 자세한 정보는 스레드 스케줄링 섹션을 참조하십시오 .)리눅스
Linux에서 Hotspot은 단순히
sched_yield()
. 이 호출의 결과는 Windows보다 약간 다르며 더 심각 할 수 있습니다.
- 양보 된 스레드는 다른 모든 스레드가 CPU 조각을 가질 때까지 다른 CPU 조각을 얻지 못합니다 .
- (적어도 커널 2.6.8 이상에서는) 스레드가 양보했다는 사실은 최근 CPU 할당에 대한 스케줄러의 휴리스틱에 의해 암시 적으로 고려됩니다. 따라서 묵시적으로 일정을 잡을 때 양보 한 스레드에 더 많은 CPU를 할당 할 수 있습니다. 미래.
( 우선 순위 및 스케줄링 알고리즘에 대한 자세한 내용 은 스레드 스케줄링 섹션을 참조하십시오 .)
언제 사용
yield()
합니까?나는 실질적으로 결코 말하지 않을 것이다. 그 동작은 표준 적으로 정의되어 있지 않으며 일반적으로 yield ()로 수행하려는 작업을 수행하는 더 좋은 방법이 있습니다.
- if you're trying to use only a portion of the CPU, you can do this in a more controllable way by estimating how much CPU the thread has used in its last chunk of processing, then sleeping for some amount of time to compensate: see the sleep() method;
- if you're waiting for a process or resource to complete or become available, there are more efficient ways to accomplish this, such as by using join() to wait for another thread to complete, using the wait/notify mechanism to allow one thread to signal to another that a task is complete, or ideally by using one of the Java 5 concurrency constructs such as a Semaphore or blocking queue.
나는 질문이 현상금과 함께 다시 활성화되어 이제 실제 용도가 무엇인지 묻습니다 yield
. 내 경험에서 예를 들어 보겠습니다.
아시다시피, yield
호출 스레드가 실행중인 프로세서를 강제로 포기하여 다른 스레드가 실행되도록 예약 할 수 있습니다. 이것은 현재 스레드가 현재 작업을 완료했지만 대기열의 맨 앞으로 빠르게 돌아가서 일부 조건이 변경되었는지 확인하려는 경우에 유용합니다. 이것은 조건 변수와 어떻게 다릅니 까? yield
스레드가 실행 상태로 훨씬 더 빨리 돌아갈 수 있도록합니다. 조건 변수를 기다릴 때 스레드는 일시 중단되고 다른 스레드가 계속해야한다는 신호를 보낼 때까지 기다려야합니다.yield
기본적으로 "다른 스레드가 실행되도록 허용하지만 내 상태에서 무언가가 매우 빠르게 변경 될 것으로 예상하면 곧 다시 작업 할 수 있습니다."라고 말합니다. 이는 상태가 빠르게 변경 될 수 있지만 스레드를 일시 중단하면 성능이 크게 저하되는 바쁜 회전을 나타냅니다.
그러나 충분히 옹알이는 구체적인 예가 있습니다. 파면 평행 패턴입니다. 이 문제의 기본 사례는 0과 1로 채워진 2 차원 배열에서 1의 개별 "섬"을 계산하는 것입니다. "섬"은 수직 또는 수평으로 서로 인접한 셀 그룹입니다.
1 0 0 0
1 1 0 0
0 0 0 1
0 0 1 1
0 0 1 1
여기에 1로 구성된 두 개의 섬이 있습니다. 왼쪽 상단과 오른쪽 하단입니다.
A simple solution is to make a first pass over the entire array and replace the 1 values with an incrementing counter such that by the end each 1 was replaced with its sequence number in row major order:
1 0 0 0
2 3 0 0
0 0 0 4
0 0 5 6
0 0 7 8
In the next step, each value is replaced by the minimum between itself and its neighbours' values:
1 0 0 0
1 1 0 0
0 0 0 4
0 0 4 4
0 0 4 4
We can now easily determine that we have two islands.
The part we want to run in parallel is the the step where we compute the minimums. Without going into too much detail, each thread gets rows in an interleaved manner and relies on the values computed by the thread processing the row above. Thus, each thread needs to slightly lag behind the thread processing the previous line, but must also keep up within reasonable time. More details and an implementation are presented by myself in this document. Note the usage of sleep(0)
which is more or less the C equivalent of yield
.
In this case yield
was used in order to force each thread in turn to pause, but since the thread processing the adjacent row would advance very quickly in the meantime, a condition variable would prove a disastrous choice.
As you can see, yield
is quite a fine-grain optimization. Using it in the wrong place e.g. waiting on a condition that changes seldomly, will cause excessive use of the CPU.
Sorry for the long babble, hope I made myself clear.
About the differences between yield()
, interrupt()
and join()
- in general, not just in Java:
- yielding: Literally, to 'yield' means to let go, to give up, to surrender. A yielding thread tells the operating system (or the virtual machine, or what not) it's willing to let other threads be scheduled in its stead. This indicates it's not doing something too critical. It's only a hint, though, and not guaranteed to have any effect.
- joining: When multiple threads 'join' on some handle, or token, or entity, all of them wait until all other relevant threads have completed execution (entirely or upto their own corresponding join). That means a bunch of threads have all completed their tasks. Then each one of these threads can be scheduled to continue other work, being able to assume all those tasks are indeed complete. (Not to be confused with SQL Joins!)
- interruption: Used by one thread to 'poke' another thread which is sleeping, or waiting, or joining - so that it is scheduled to continue running again, perhaps with an indication it has been interrupted. (Not to be confused with hardware interrupts!)
For Java specifically, see
Joining:
How to use Thread.join? (here on StackOverflow)
Yielding:
Interrupting:
Is Thread.interrupt() evil? (here on StackOverflow)
First, the actual description is
Causes the currently executing thread object to temporarily pause and allow other threads to execute.
Now, it is very likely that your main thread will execute the loop five times before the run
method of the new thread is being executed, so all the calls to yield
will happen only after the loop in the main thread is executed.
join
will stop the current thread until the thread being called with join()
is done executing.
interrupt
will interrupt the thread it is being called on, causing InterruptedException.
yield
allows a context switch to other threads, so this thread will not consume the entire CPU usage of the process.
The current answer(s) are out-of-date and require revision given recent changes.
There is no practical difference of Thread.yield()
between Java versions since 6 to 9.
TL;DR;
Conclusions based on OpenJDK source code (http://hg.openjdk.java.net/).
If not to take into account HotSpot support of USDT probes (system tracing information is described in dtrace guide) and JVM property ConvertYieldToSleep
then source code of yield()
is almost the same. See explanation below.
Java 9:
Thread.yield()
calls OS-specific method os::naked_yield()
:
On Linux:
void os::naked_yield() {
sched_yield();
}
On Windows:
void os::naked_yield() {
SwitchToThread();
}
Java 8 and earlier:
Thread.yield()
calls OS-specific method os::yield()
:
On Linux:
void os::yield() {
sched_yield();
}
On Windows:
void os::yield() { os::NakedYield(); }
As you can see, Thread.yeald()
on Linux is identical for all Java versions.
Let's see Windows's os::NakedYield()
from JDK 8:
os::YieldResult os::NakedYield() {
// Use either SwitchToThread() or Sleep(0)
// Consider passing back the return value from SwitchToThread().
if (os::Kernel32Dll::SwitchToThreadAvailable()) {
return SwitchToThread() ? os::YIELD_SWITCHED : os::YIELD_NONEREADY ;
} else {
Sleep(0);
}
return os::YIELD_UNKNOWN ;
}
The difference between Java 9 and Java 8 in the additional check of the existence of the Win32 API's SwitchToThread()
method. The same code is present for Java 6.
Source code of os::NakedYield()
in JDK 7 is slightly different but it has the same behavior:
os::YieldResult os::NakedYield() {
// Use either SwitchToThread() or Sleep(0)
// Consider passing back the return value from SwitchToThread().
// We use GetProcAddress() as ancient Win9X versions of windows doen't support SwitchToThread.
// In that case we revert to Sleep(0).
static volatile STTSignature stt = (STTSignature) 1 ;
if (stt == ((STTSignature) 1)) {
stt = (STTSignature) ::GetProcAddress (LoadLibrary ("Kernel32.dll"), "SwitchToThread") ;
// It's OK if threads race during initialization as the operation above is idempotent.
}
if (stt != NULL) {
return (*stt)() ? os::YIELD_SWITCHED : os::YIELD_NONEREADY ;
} else {
Sleep (0) ;
}
return os::YIELD_UNKNOWN ;
}
The additional check has been dropped due to SwitchToThread()
method are available since Windows XP and Windows Server 2003 (see msdn notes).
What are, in fact, the main uses of yield()?
Yield suggests to the CPU that you may stop the current thread and start executing threads with higher priority. In other words, assigning a low priority value to the current thread to leave room for more critical threads.
I believe the code below result in the same output both when using yield() and when not using it. Is this correct?
NO, the two will produce different results. Without a yield(), once the thread gets control it will execute the 'Inside run' loop in one go. However, with a yield(), once the thread gets control it will print the 'Inside run' once and then will hand over control to other thread if any. If no thread in pending, this thread will be resumed again. So every time "Inside run' is executed it will look for other threads to execute and if no thread is available, the current thread will keep on executing.
In what ways is yield() different from the join() and interrupt() methods?
yield() is for giving room to other important threads, join() is for waiting for another thread to complete its execution, and interrupt() is for interrupting a currently executing thread to do something else.
Thread.yield()
causes thread to go from "Running" state to "Runnable" state. Note: It doesn't cause thread to go "Waiting" state.
Thread.yield()
When we invoke Thread.yield() method, the thread scheduler keep the currently running thread to Runnable state and picks another thread of equal priority or higher priority. If there is no equal and higher priority thread then it reschedule the calling yield() thread. Remember yield method does not make the thread to go to Wait or Blocked state. It can only make a thread from Running State to Runnable State.
join()
When join is invoked by a thread instance, this thread will tell currently executing thread to wait till the Joining thread completes. Join is used in the situations when a task which should be completed before the current task is going to finish.
yield() main use is for putting a multi-threading application on hold.
all these methods differences are yield() puts thread on hold while executing another thread and returning back after the completion of that thread, join() will bring the beginning of threads together executing until the end and of another thread to run after that thread has ended, interrupt() will stop the execution of a thread for a while.
'Programming' 카테고리의 다른 글
프로그래밍 방식으로 기기의 Android API 수준을 얻습니까? (0) | 2020.08.23 |
---|---|
예외가 발생할 때까지 GDB에서 응용 프로그램 실행 (0) | 2020.08.23 |
범위 생성에서 '..'(이중 점)과 '…'(삼중 점)의 차이점은 무엇입니까? (0) | 2020.08.23 |
Ruby 배열 : select (), collect () 및 map () (0) | 2020.08.23 |
콘솔에서 C로 줄을 읽는 방법은 무엇입니까? (0) | 2020.08.23 |