簡體   English   中英

方法收益如何運作?

[英]How does method yield work?

在javadoc中有說yield方法

導致當前正在執行的線程對象暫時暫停並允許其他線程執行。

Katherine Sierra和Bert Bates的SCJP書中說過

yield()應該做的是使當前運行的線程返回runnable以允許具有相同優先級的其他線程輪到他們。

那么實際的方法是做什么的?

給定一個多線程應用程序, yield將導致當前正在執行的線程暫停執行並設置為等待狀態。 然后,JVM將開始運行另一個先前處於等待狀態的線程。

我相信剛剛產生的同一個線程在技術上可以安排再次啟動。

而且我還沒有在野外看到這一點。 所以我覺得避免安全。

詳細說明:

在多線程環境中,線程是在JVM的意願下調度和打開的。 因此,即使在代碼中沒有調用yield,當JVM決定它應該時,你的線程可以/將自動屈服於其他線程。 這允許多線程在僅具有一個處理核心的環境中工作。

調用yield只是告訴JVM將當前線程置於等待狀態,即使JVM不會。

我將嘗試一個例子:
以下是隨着時間的推移執行2個線程的非常簡化的說明(假設1個核心) -

Thread\Time    1    2    3    4    5    6    7    8    9
Thread 1    -----------       -----          -------
Thread 2               -------     ----------       ------

每當你看到'-'表示線程正在執行。 A ' '表示線程正在等待。 如您所見,一次只能運行一個線程。 因此,當1次運行時,另一次等待。 要產生的收益是讓其他線程有機會在當前運行的線程之前運行。

線程可以處於准備狀態(可運行),阻塞狀態(例如,等待某些io完成)或運行; 這對於所有線程實現都是通用的,盡管某些特定實現可能具有更多狀態。

Yield會導致線程從運行更改為可運行,並等待調度程序將來再次將其更改為運行。 這就是SCJP書中的含義。

對於線程,它似乎暫停了一段時間,就像在javadoc中描述的那樣。 所以這兩個陳述都是正確的,只是用不同的措辭。

yield()通常用於等待線程發生某些事情但不想用while(condition){ ...}來阻止CPC周期。 yield()的工作方式因平台而異,取決於線程調度程序,您不應該依賴於它以特定方式運行。

它起源於合作多任務的時間。 基本思想是,處理器只執行一個線程,直到:

  1. 這個帖子結束了
  2. 這個線程執行一些阻塞操作,比如object.wait()Thread.sleep ,等待一些IO操作完成,等待某個對象監視器或類似操作。
  3. 這個線程調用Thread.yield()

在每種情況下,線程調度程序然后選擇另一個要執行的線程。 因此,為了公平對待其他線程,您可以在沒有任何阻塞操作的較長循環中定期調用yield() (如果沒有其他線程准備好運行,則會再次安排相同的線程,因此不會造成很大的性能損失。)

在現代VM中,線程切換可以在任何點上發生,不僅這些列出的線程甚至可以同時執行,因此它不是必需的,並且一些VM可能完全忽略它(類似於System.gc() 。)

yield()方法用於確保應用程序中的所有相同優先級線程不會導致飢餓 例如,應用程序中存在五個線程,並且所有線程具有相同的優先級。 現在假設一個線程有機會運行,這個線程需要很長時間來完成它的任務,因此其他線程不會有機會運行。 所以為了避免這種情況,yield()就可以解救了。

最終,對yield()的調用導致調用這樣的os方法,原則上它會將任務本身放回到運行隊列中並讓下一個任務運行( ):

 /**
  * sys_sched_yield - yield the current processor to other threads.
  *
  * This function yields the current CPU to other tasks. If there are no
  * other threads running on this CPU then this function will return.
  */
 SYSCALL_DEFINE0(sched_yield)
 {
        /*
         *  lock this runqueue and disable interrupts.
         */
         struct rq *rq = this_rq_lock();

         schedstat_inc(rq, yld_count);
         current->sched_class->yield_task(rq);

         /*
          * Since we are going to call schedule() anyway, there's
          * no need to preempt or enable interrupts:
          */
         __release(rq->lock);
         spin_release(&rq->lock.dep_map, 1, _THIS_IP_);
         _raw_spin_unlock(&rq->lock);
         preempt_enable_no_resched();

         schedule();

         return 0;
 }

希望能幫助到你!

package yield;

public class ThreadYieldApp {

    Thread th1 = new Thread("Thread 1") {
        public void run() {

            for(int i = 0; i <= 10; i++) {
                System.out.println("Before Yield - " + Thread.currentThread().getName() + " at index - " + i);
                //Currently pauses the thread and checks for other threads of same priority, and passes control to it based on Thread Scheduler pick 
                Thread.yield();
                System.out.println("Currently running - " + Thread.currentThread().getName() + " at index - " + i);
            }
        }
    };

    Thread th2 = new Thread("Thread 2") {
        public void run() {
            for(int i = 0; i <= 10; i++) {
                System.out.println("Currently running - " + Thread.currentThread().getName() + " at index - " + i);
            }
        }
    };


    public static void main(String[] args) {
        ThreadYieldApp threadYieldApp = new ThreadYieldApp();
        threadYieldApp.th1.start();
        threadYieldApp.th2.start();
    }

    //Happy coding -- Parthasarathy S
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM