yield ()의 주요 용도는 무엇이며 join () 및 interrupt ()와 어떻게 다릅니 까?


106

yield()특히 아래 예제 코드에서 Java 의 메서드 사용에 대해 약간 혼란스러워 합니다. 또한 yield ()는 '스레드 실행을 방지하는 데 사용됨'을 읽었습니다.

내 질문은 다음과 같습니다.

  1. 아래 코드는 사용할 때 yield()와 사용하지 않을 때 모두 동일한 결과를 산출한다고 생각합니다 . 이 올바른지?

  2. 실제로의 주요 용도는 yield()무엇입니까?

  3. 및 방법 과 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

이 질문은 너무 광범위 하기 때문에 닫아야합니다 .
Raedwald 2014

아니요 yield(). 가지고있는 경우 와없는 경우 동일한 결과를 반환하지 않습니다. 5가 아닌 i가 크면 yield()방법 의 효과를 볼 수 있습니다 .
락스

답변:


97

출처 : 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()Windows SwitchToThread()API 호출을 사용하여 구현 됩니다 . 이 호출은 현재 스레드 가 전체 퀀텀이 아닌 현재 타임 슬라이스를 포기하도록합니다 . 이는 다른 스레드의 우선 순위에 따라 양보 스레드가 나중에 한 인터럽트 기간으로 다시 예약 될 수 있음을 의미합니다 . ( 타임 슬라이스에 대한 자세한 정보는 스레드 스케줄링 섹션을 참조하십시오 .)

리눅스

Linux에서 Hotspot은 단순히 sched_yield(). 이 호출의 결과는 Windows보다 약간 다르며 더 심각 할 수 있습니다.

  • 양보 된 스레드는 다른 모든 스레드가 CPU 조각을 가질 때까지 다른 CPU 조각을 얻지 못합니다 .
  • (적어도 커널 2.6.8 이상에서는) 스레드가 양보했다는 사실은 최근 CPU 할당에 대한 스케줄러의 휴리스틱에 의해 암시 적으로 고려됩니다. 따라서 묵시적으로 일정을 잡을 때 양보 한 스레드에 더 많은 CPU를 할당 할 수 있습니다. 미래.

( 우선 순위 및 스케줄링 알고리즘에 대한 자세한 내용 은 스레드 스케줄링 섹션을 참조하십시오 .)

언제 사용 yield()합니까?

나는 실질적으로 결코 말하지 않을 것이다. 그 동작은 표준 적으로 정의되어 있지 않으며 일반적으로 yield ()로 수행하려는 작업을 수행하는 더 좋은 방법이 있습니다.

  • CPU의 일부만 사용 하려는 경우 스레드가 마지막 처리 청크에서 사용한 CPU 양을 추정 한 다음 보상을 위해 일정 시간 동안 잠자기 때문에보다 제어 가능한 방식으로이를 수행 할 수 있습니다 . 슬립 () 메소드;
  • 있는 거 당신이 경우 프로세스 또는 자원에 대한 대기 가능하게 완료 또는,이보다 효율적으로 같은 사용하여 같은 이러한 목표를 달성 할 수있는 방법이다 ()에 가입 완료하기 위해 다른 스레드를 기다릴의 사용 / 대기를 통지 하나 개의 스레드를 허용하는 메커니즘을 태스크가 완료되었음을 다른 사람에게 알리거나 이상적으로는 Semaphore 또는 블로킹 큐 와 같은 Java 5 동시성 구성 중 하나를 사용하여 신호를 보냅니다 .

18
"양자 남아", "전체 양자는"- 방식 누군가를 따라 어딘가에는 어떤 단어 "양자"수단 잊어
kbolino을

@kbolino Quantum은 새로운 원자입니다.
Evgeni Sergeev

2
@kbolino-... 라틴어 : "만큼", "얼마나" . 나는 이것이 위의 사용과 어떤 식 으로든 모순되는 것을 보지 못합니다. 이 단어는 단순히 설명 된 양을 의미하므로 사용 된 부분과 남은 부분으로 나누는 것이 나에게 완벽하게 합리적이라고 생각합니다.
Periata Breatta 2016

@PeriataBreatta 물리학 이외의 단어에 익숙하다면 더 의미가 있다고 생각합니다. 내가 아는 것은 물리학 적 정의뿐이었습니다.
kbolino 2016

이 답변을 7, 8, 9에 대해 업데이트하기 위해이 질문에 현상금을 걸었습니다. 7,8 및 8에 대한 최신 정보로 수정하면 현상금을 받게됩니다.

40

나는 질문이 현상금과 함께 다시 활성화되어 이제 실제 용도가 무엇인지 묻습니다 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로 구성된 두 개의 섬이 있습니다. 왼쪽 상단과 오른쪽 하단입니다.

간단한 해결책은 전체 배열에 대한 첫 번째 패스를 만들고 1 값을 증분 카운터로 대체하여 끝까지 각 1이 행 주요 순서의 시퀀스 번호로 대체되도록하는 것입니다.

1 0 0 0
2 3 0 0
0 0 0 4
0 0 5 6
0 0 7 8

다음 단계에서 각 값은 자신과 이웃 값 사이의 최소값으로 대체됩니다.

1 0 0 0
1 1 0 0
0 0 0 4
0 0 4 4
0 0 4 4

이제 두 개의 섬이 있음을 쉽게 확인할 수 있습니다.

병렬로 실행하려는 부분은 최소값을 계산하는 단계입니다. 너무 자세히 설명하지 않고 각 스레드는 인터리브 방식으로 행을 가져오고 위의 행을 처리하는 스레드가 계산 한 값에 의존합니다. 따라서 각 스레드는 이전 행을 처리하는 스레드보다 약간 뒤쳐 져야하지만 적절한 시간 내에 유지되어야합니다. 자세한 내용과 구현은 이 문서 에서 직접 제공 합니다 . 의 사용법 sleep(0)yield.

이 경우 yield각 스레드를 강제로 일시 중지하기 위해 사용되었지만 인접한 행을 처리하는 스레드가 그 동안 매우 빠르게 진행되므로 조건 변수는 비참한 선택이 될 것입니다.

보시다시피, yield상당히 세분화 된 최적화입니다. 엉뚱한 장소에서 사용하는 경우 (예 : 거의 변경되지 않는 상태에서 기다리는 경우) CPU를 과도하게 사용하게됩니다.

긴 옹알이에 대해 죄송합니다.


1
IIUC 문서에 제시 한 내용은이 경우 바쁘게 대기하는 것이 더 효율적 yield이라는 것입니다. 조건이 만족스럽지 않을 때 호출 하여 다른 스레드가 계산을 진행할 수있는 기회를 더 많이 사용하는 것보다 레벨 동기화 프리미티브 맞죠?
페트르 Pudlák

3
@Petr Pudlák : 네. 스레드 시그널링을 사용하는 것과 비교하여 벤치마킹했으며이 경우 성능 차이가 컸습니다. 조건이 매우 빠르게 참이 될 수 있기 때문에 (핵심 문제), .NET을 사용하여 매우 짧은 기간 동안 CPU를 포기하는 대신 OS에 의해 스레드가 보류되기 때문에 조건 변수가 너무 느립니다 yield.
Tudor

@Tudor 훌륭한 설명!
개발자 마리우스 Žilėnas

1
"수율의 C에 상당하는 수면 (0)의 사용법에 유의하십시오.".. 음, Java와 함께 sleep (0)을 원한다면 왜 그냥 사용하지 않겠습니까? Thread.sleep ()은 이미 존재하는 것입니다. 이 답변이 Thread.sleep (0) 대신 Thread.yield ()를 사용하는 이유에 대한 추론을 제공하는지 확실하지 않습니다. 다른 이유를 설명 하는 기존 스레드 도 있습니다 .
eis

@eis : Thread.sleep (0) 대 Thread.yield ()는이 답변의 범위를 벗어납니다. 나는 C에서 비슷한 것을 찾는 사람들을 위해서만 Thread.sleep (0)을 언급했다. 질문은 Thread.yield ()의 사용에 관한 것이었다.
Tudor

12

yield(), interrupt()join()-일반적으로 Java뿐만 아니라 차이점에 대해 :

  1. yielding : 말 그대로 '양보하다'는 것은 놓아주고, 포기하고, 항복하는 것을 의미합니다. 양보하는 스레드는 대신 다른 스레드가 예약되도록 허용 할 의사가있는 운영 체제 (또는 가상 머신 또는 그렇지 않은 것)를 알려줍니다. 이것은 너무 비판적인 일을하고 있지 않다는 것을 나타냅니다. 그러나 힌트 일 뿐이며 효과가 보장되지는 않습니다.
  2. joining : 여러 스레드가 일부 핸들, 토큰 또는 엔터티에 'join'할 때 모든 다른 관련 스레드가 실행을 완료 할 때까지 (전체적으로 또는 해당 결합까지) 기다립니다. 이는 많은 스레드가 모두 작업을 완료했음을 의미합니다. 그런 다음 이러한 스레드 각각은 다른 작업을 계속하도록 예약 할 수 있으며 이러한 모든 작업이 실제로 완료되었다고 가정 할 수 있습니다. (SQL 조인과 혼동하지 마십시오!)
  3. interruption : 한 스레드가 대기 중이거나 대기 중이거나 참여중인 다른 스레드를 '포킹'하는 데 사용되므로 중단되었음을 표시하면서 다시 계속 실행되도록 예약됩니다. (하드웨어 인터럽트와 혼동하지 마십시오!)

특히 Java의 경우

  1. 합류:

    Thread.join을 사용하는 방법? (여기 StackOverflow에서)

    스레드를 언제 결합해야합니까?

  2. 굽힐 수 있는:

  3. 중단 :

    Thread.interrupt ()가 사악합니까? (여기 StackOverflow에서)


핸들 또는 토큰을 결합한다는 것은 무엇을 의미합니까? wait () 및 notify () 메서드는 Object에 있으므로 사용자가 임의의 Object를 기다릴 수 있습니다. 그러나 join ()은 덜 추상적 인 것처럼 보이며 계속하기 전에 완료하려는 특정 스레드에서 호출해야합니다 ... 그렇지 않습니까?
spaaarky21 2014 년

@ spaaarky21 : 나는 일반적으로 자바에서 꼭 필요한 것은 아니다. 또한 a wait()는 조인이 아니며 호출하는 스레드가 획득하려고하는 객체에 대한 잠금에 관한 것입니다. 다른 사용자가 잠금을 해제하고 스레드가 획득 할 때까지 기다립니다. 그에 따라 내 대답을 조정했습니다.
einpoklum 2014 년

10

첫째, 실제 설명은

현재 실행중인 스레드 개체가 일시적으로 일시 중지되고 다른 스레드가 실행되도록합니다.

이제 run새 스레드 의 메서드 가 실행되기 전에 메인 스레드가 루프를 5 번 실행할 가능성이 높 으므로 모든 호출 yield은 메인 스레드의 루프가 실행 된 후에 만 ​​발생합니다.

join호출되는 스레드가 join()실행을 완료 할 때까지 현재 스레드를 중지합니다 .

interrupt호출되는 스레드를 중단하여 InterruptedException을 발생시킵니다 .

yield 다른 스레드로 컨텍스트 전환을 허용하므로이 스레드는 프로세스의 전체 CPU 사용량을 소비하지 않습니다.


+1. 또한 yield ()를 호출 한 후에도 동일한 우선 순위 스레드 풀이 주어지면 동일한 스레드가 다시 실행되도록 선택되지 않는다는 보장이 없습니다.
Andrew Fielden 2011-08-08

그러나 SwitchToThread()전화는 더 나은 수면 (0)보다 이것은 : 자바에서 버그가 수 있어야
Петър Петров

4

현재 답변이 오래되었으며 최근 변경 사항에 따라 수정해야합니다.

6-9 이후 Java 버전간에 실질적인 차이 는 없습니다 Thread.yield().

TL; DR;

OpenJDK 소스 코드 ( http://hg.openjdk.java.net/ ) 에 기반한 결론입니다 .

USDT 프로브 (시스템 추적 정보는 dtrace 가이드에 설명되어 있음 ) 및 JVM 속성의 HotSpot 지원을 고려하지 않으면의 ConvertYieldToSleep소스 코드 yield()는 거의 동일합니다. 아래 설명을 참조하십시오.

자바 9 :

Thread.yield()OS 별 메서드 호출 os::naked_yield():
Linux에서 :

void os::naked_yield() {
    sched_yield();
}

Windows의 경우 :

void os::naked_yield() {
    SwitchToThread();
}

Java 8 이하 :

Thread.yield()OS 별 메서드 호출 os::yield():
Linux에서 :

void os::yield() {
    sched_yield();
}

Windows의 경우 :

void os::yield() {  os::NakedYield(); }

보시다시피 Thread.yeald()Linux에서는 모든 Java 버전이 동일합니다. JDK 8에서
Windows를 살펴 보겠습니다 os::NakedYield().

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 ;
}

Win32 API SwitchToThread()메서드 의 존재에 대한 추가 검사에서 Java 9와 Java 8의 차이점 . Java 6에도 동일한 코드가 있습니다 . JDK 7
의 소스 코드 os::NakedYield()는 약간 다르지만 동작은 같습니다.

    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 ;
}

SwitchToThread()Windows XP 및 Windows Server 2003부터 사용할 수있는 방법 으로 인해 추가 검사가 삭제되었습니다 ( msdn 참고 사항 참조 ).


2

실제로 yield ()의 주요 용도는 무엇입니까?

Yield는 CPU에 현재 스레드를 중지하고 더 높은 우선 순위로 스레드 실행을 시작할 수 있음을 제안합니다. 즉, 더 중요한 스레드를위한 공간을 남겨두기 위해 현재 스레드에 낮은 우선 순위 값을 할당합니다.

아래 코드는 yield ()를 사용할 때와 사용하지 않을 때 모두 동일한 출력을 생성한다고 생각합니다. 이 올바른지?

아니요, 둘은 다른 결과를 생성합니다. yield ()가 없으면 스레드가 제어를 받으면 'Inside run'루프가 한 번에 실행됩니다. 그러나 yield ()를 사용하면 스레드가 제어를 받으면 'Inside run'을 한 번 인쇄 한 다음 제어권을 다른 스레드에 넘겨줍니다. 보류중인 스레드가 없으면이 스레드가 다시 재개됩니다. 따라서 "Inside run"이 실행될 때마다 실행할 다른 스레드를 찾고 사용 가능한 스레드가 없으면 현재 스레드가 계속 실행됩니다.

yield ()는 join () 및 interrupt () 메서드와 어떤 점에서 다릅니 까?

yield ()는 다른 중요한 스레드에 공간을 제공하고 join ()은 다른 스레드가 실행을 완료 할 때까지 대기하며 interrupt ()는 현재 실행중인 스레드를 중단하여 다른 작업을 수행합니다.


이 진술이 사실인지 확인하고 싶 Without a yield(), once the thread gets control it will execute the 'Inside run' loop in one go습니까? 명확히하십시오.
Abdullah Khan

0

Thread.yield()스레드가 "실행 중"상태에서 "실행 가능"상태로 이동합니다. 참고 : 스레드가 "대기 중"상태가되지는 않습니다.


@PJMeisch, 인스턴스에 RUNNING대한 상태 가 없습니다 java.lang.Thread. 그러나 Thread인스턴스가 프록시 인 네이티브 스레드에 대한 네이티브 "실행 중"상태를 배제하지는 않습니다 .
Solomon Slow

-1

Thread.yield ()

Thread.yield () 메서드를 호출 할 때 스레드 스케줄러는 현재 실행중인 스레드를 Runnable 상태로 유지하고 우선 순위가 같거나 더 높은 다른 스레드를 선택합니다. 동일하고 우선 순위가 높은 스레드가 없으면 호출 yield () 스레드를 다시 예약합니다. yield 메서드는 스레드를 Wait 또는 Blocked 상태로 만들지 않습니다. 스레드를 Running State에서 Runnable State로만 만들 수 있습니다.

붙다()

스레드 인스턴스에 의해 join이 호출되면이 스레드는 현재 실행중인 스레드에 Joining 스레드가 완료 될 때까지 기다리도록 지시합니다. Join은 현재 작업이 완료되기 전에 완료되어야하는 작업이있는 상황에서 사용됩니다.


-4

yield () 주요 용도는 다중 스레딩 응용 프로그램을 보류하는 것입니다.

이러한 모든 메서드 차이점은 yield () 다른 스레드를 실행하는 동안 스레드를 보류하고 해당 스레드가 완료된 후 다시 돌아 오면 join ()은 스레드가 끝날 때까지 스레드의 시작을 함께 실행하고 해당 스레드가 실행 된 후에 다른 스레드가 실행되도록합니다. 종료되면, interrupt ()는 잠시 스레드의 실행을 중지합니다.


답변 주셔서 감사합니다. 그러나 다른 답변이 이미 자세히 설명하는 것을 반복합니다. 사용해야하는 적절한 사용 사례에 대한 현상금을 제공하고 yield있습니다.
Petr Pudlák 2014 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.