Heim  >  Artikel  >  Java  >  Der Unterschied zwischen Yield- und Join-Methoden in Java-Threads

Der Unterschied zwischen Yield- und Join-Methoden in Java-Threads

伊谢尔伦
伊谢尔伦Original
2016-11-26 11:54:571475Durchsuche

Multithreading-Fragen werden seit langem von Interviewern bevorzugt. Obwohl ich persönlich glaube, dass nur wenige von uns tatsächlich die Chance bekommen, komplexe Multithread-Anwendungen zu entwickeln (ich habe in den letzten sieben Jahren eine bekommen), kann das Verständnis von Multithreading hilfreich sein, um Ihr Selbstvertrauen zu stärken. Zuvor habe ich den Unterschied zwischen den Methoden „wait()“ und „sleep()“ besprochen. Dieses Mal werde ich den Unterschied zwischen den Methoden „join()“ und „yield()“ besprechen. Um ehrlich zu sein, habe ich keine dieser Methoden tatsächlich angewendet. Wenn Sie also das Gefühl haben, dass etwas unangemessen ist, besprechen Sie es bitte.

Ein kleiner Hintergrund zur Java-Thread-Planung

In verschiedenen Threads muss die Java Virtual Machine einen priorisierten, prioritätsbasierten Scheduler implementieren. Dies bedeutet, dass jedem Thread in einem Java-Programm eine bestimmte Priorität zugewiesen wird, dargestellt durch eine positive Ganzzahl innerhalb eines definierten Bereichs. Prioritäten können von Entwicklern geändert werden. Selbst wenn der Thread eine bestimmte Zeit lang ausgeführt wurde, ändert die Java Virtual Machine ihre Priorität nicht

Der Prioritätswert ist wichtig, da die Vereinbarung zwischen der Java Virtual Machine und dem zugrunde liegenden Betriebssystem darin besteht, dass die Das Betriebssystem muss sich dafür entscheiden, den Java-Thread mit der höchsten Priorität auszuführen. Wir sagen also, dass Java einen prioritätsbasierten Scheduler implementiert. Der Scheduler ist prioritätsorientiert implementiert, was bedeutet, dass beim Eintreffen eines Threads mit höherer Priorität dieser unterbrochen (vorbelegt) wird, unabhängig davon, ob der Thread mit niedrigerer Priorität ausgeführt wird. Diese Konvention trifft nicht immer auf das Betriebssystem zu, was bedeutet, dass das Betriebssystem manchmal beschließt, einen Thread mit niedrigerer Priorität auszuführen. (Ich hasse diesen Aspekt des Multithreadings, weil er nichts garantiert)

Beachten Sie, dass Java die Ausführung von Threads nicht auf Zeitscheiben beschränkt, die meisten Betriebssysteme jedoch schon. Häufige Verwirrung in der Terminologie: Preemption wird oft mit Time Slicing verwechselt. Tatsächlich bedeutet Vorbelegung, dass nur Threads mit hoher Priorität vor Threads mit niedriger Priorität ausgeführt werden können. Wenn Threads jedoch dieselbe Priorität haben, können sie sich nicht gegenseitig vorbelegen. Normalerweise werden sie in Zeitscheiben unterteilt, dies ist jedoch keine Anforderung von Java.

Thread-Prioritäten verstehen

Als nächstes ist das Verständnis der Thread-Prioritäten ein wichtiger Schritt beim Multithreading-Lernen, insbesondere das Verständnis des Arbeitsprozesses der yield()-Funktion.

Denken Sie daran, dass, wenn die Priorität eines Threads nicht angegeben ist, alle Threads die normale Priorität haben.

Priorität kann in einem Bereich von 1 bis 10 angegeben werden. 10 steht für die höchste Priorität, 1 für die niedrigste Priorität und 5 für die normale Priorität.

Denken Sie daran, dass der Thread mit der höchsten Priorität bei der Ausführung Priorität erhält. Es gibt jedoch keine Garantie dafür, dass der Thread beim Starten in den Ausführungsstatus wechselt.

Der aktuell laufende Thread hat möglicherweise immer eine höhere Priorität als der Thread, der im Thread-Pool auf eine Chance zur Ausführung wartet.

Der Scheduler entscheidet, welcher Thread ausgeführt wird.

t.setPriority() wird verwendet, um die Priorität des Threads festzulegen.

Denken Sie daran, dass die Priorität des Threads festgelegt werden sollte, bevor die Thread-Startmethode aufgerufen wird.

Sie können Konstanten wie MIN_PRIORITY, MAX_PRIORITY, NORM_PRIORITY verwenden, um die Priorität festzulegen

Wenn wir nun ein gewisses Verständnis für Thread-Planung und Thread-Priorität haben, beginnen wir mit dem Thema.

Yield()-Methode

Theoretisch bedeutet Yield loslassen, aufgeben, kapitulieren. Ein Thread, der die Methode yield() aufruft, teilt der virtuellen Maschine mit, dass er bereit ist, andere Threads seine Position besetzen zu lassen. Dies weist darauf hin, dass der Thread keine dringende Aufgabe erledigt. Beachten Sie, dass dies nur ein Hinweis ist und nicht garantiert, dass es keine Auswirkungen hat.

Yield() in Thread.java ist wie folgt definiert:

/**
  * A hint to the scheduler that the current thread is willing to yield its current use of a processor. The scheduler is free to ignore
  * this hint. Yield is a heuristic attempt to improve relative progression between threads that would otherwise over-utilize a CPU.
  * Its use should be combined with detailed profiling and benchmarking to ensure that it actually has the desired effect.
  */
 
public static native void yield();

Lassen Sie uns einige wichtige Punkte zur obigen Definition auflisten:

Yield ist ein statisches Native (native) Methode

Yield weist den aktuell ausgeführten Thread an, Threads mit derselben Priorität im Thread-Pool die Möglichkeit zum Ausführen zu geben.

Yield garantiert nicht, dass der aktuell laufende Thread schnell in einen ausführbaren Zustand übergeht

Es kann einen Thread nur von einem laufenden Zustand in einen ausführbaren Zustand überführen, nicht in einen Warte- oder Blockierungszustand

Beispiel für die Verwendung der yield()-Methode

在下面的示例程序中,我随意的创建了名为生产者和消费者的两个线程。生产者设定为最小优先级,消费者设定为最高优先级。在Thread.yield()注释和非注释的情况下我将分别运行该程序。没有调用yield()方法时,虽然输出有时改变,但是通常消费者行先打印出来,然后事生产者。

调用yield()方法时,两个线程依次打印,然后将执行机会交给对方,一直这样进行下去。

package test.core.threads;
 
public class YieldExample
{
   public static void main(String[] args)
   {
      Thread producer = new Producer();
      Thread consumer = new Consumer();
 
      producer.setPriority(Thread.MIN_PRIORITY); //Min Priority
      consumer.setPriority(Thread.MAX_PRIORITY); //Max Priority
 
      producer.start();
      consumer.start();
   }
}
 
class Producer extends Thread
{
   public void run()
   {
      for (int i = 0; i < 5; i++)
      {
         System.out.println("I am Producer : Produced Item " + i);
         Thread.yield();
      }
   }
}
 
class Consumer extends Thread
{
   public void run()
   {
      for (int i = 0; i < 5; i++)
      {
         System.out.println("I am Consumer : Consumed Item " + i);
         Thread.yield();
      }
   }
}

上述程序在没有调用yield()方法情况下的输出:

I am Consumer : Consumed Item 0
 I am Consumer : Consumed Item 1
 I am Consumer : Consumed Item 2
 I am Consumer : Consumed Item 3
 I am Consumer : Consumed Item 4
 I am Producer : Produced Item 0
 I am Producer : Produced Item 1
 I am Producer : Produced Item 2
 I am Producer : Produced Item 3
 I am Producer : Produced Item 4

    上述程序在调用yield()方法情况下的输出:

I am Producer : Produced Item 0
 I am Consumer : Consumed Item 0
 I am Producer : Produced Item 1
 I am Consumer : Consumed Item 1
 I am Producer : Produced Item 2
 I am Consumer : Consumed Item 2
 I am Producer : Produced Item 3
 I am Consumer : Consumed Item 3
 I am Producer : Produced Item 4
 I am Consumer : Consumed Item 4

join()方法

线程实例的方法join()方法可以使得在另一个线程的执行结束后再开始执行这个线程。如果join()方法被在一个线程实例上调用,当前运行着的线程将阻塞直到线程实例完成了执行。

//Waits for this thread to die.
 
public final void join() throws InterruptedException

在join()方法内设定超时,使得join()方法的影响在特定超时后无效。当超时时,主方法和任务线程申请运行的时候是平等的。然而,当涉及sleep时,join()方法依靠操作系统计时,所以你不应该假定join()方法将会等待你指定的时间。

像sleep,join通过抛出InterruptedException对中断做出回应。

join()方法使用示例

package test.core.threads;
 
public class JoinExample
{
   public static void main(String[] args) throws InterruptedException
   {
      Thread t = new Thread(new Runnable()
         {
            public void run()
            {
               System.out.println("First task started");
               System.out.println("Sleeping for 2 seconds");
               try
               {
                  Thread.sleep(2000);
               } catch (InterruptedException e)
               {
                  e.printStackTrace();
               }
               System.out.println("First task completed");
            }
         });
      Thread t1 = new Thread(new Runnable()
         {
            public void run()
            {
               System.out.println("Second task completed");
            }
         });
      t.start(); // Line 15
      t.join(); // Line 16
      t1.start();
   }
}
 
Output:
 
First task started
Sleeping for 2 seconds
First task completed
Second task completed


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn