Estoy un poco confundido sobre el uso del yield()
método en Java, específicamente en el código de ejemplo a continuación. También he leído que yield () se 'usa para evitar la ejecución de un hilo'.
Mis preguntas son:
Creo que el siguiente código da como resultado el mismo resultado tanto cuando se usa
yield()
como cuando no se usa. ¿Es esto correcto?¿Cuáles son, de hecho, los principales usos de
yield()
?¿En qué se
yield()
diferencia de los métodosjoin()
yinterrupt()
?
El ejemplo de código:
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();
}
}
}
Obtengo el mismo resultado usando el código anterior con y sin usar yield()
:
Inside main
Inside main
Inside main
Inside main
Inside main
Inside run
Inside run
Inside run
Inside run
Inside run
yield()
y no. cuando tiene una i grande en lugar de 5, puede ver el efecto delyield()
método.Respuestas:
Fuente: http://www.javamex.com/tutorials/threads/yield.shtml
fuente
Veo que la pregunta se ha reactivado con una recompensa, ahora preguntando cuáles son los usos prácticos
yield
. Daré un ejemplo de mi experiencia.Como sabemos,
yield
obliga al subproceso que realiza la llamada a abandonar el procesador en el que se está ejecutando para que se pueda programar la ejecución de otro subproceso. Esto es útil cuando el hilo actual ha terminado su trabajo por ahora pero quiere volver rápidamente al frente de la cola y verificar si alguna condición ha cambiado. ¿En qué se diferencia de una variable de condición?yield
permite que el hilo vuelva mucho más rápido a un estado de ejecución. Cuando se espera una variable de condición, el subproceso se suspende y debe esperar a que un subproceso diferente indique que debe continuar.yield
básicamente dice "permitir que se ejecute un hilo diferente, pero permitirme volver al trabajo muy pronto, ya que espero que algo cambie en mi estado muy, muy rápidamente". Esto sugiere un giro ocupado, donde una condición puede cambiar rápidamente pero suspender el hilo incurriría en un gran impacto en el rendimiento.Pero basta de balbucear, aquí hay un ejemplo concreto: el patrón paralelo de frente de onda. Un ejemplo básico de este problema es calcular las "islas" individuales de 1 en una matriz bidimensional llena de 0 y 1. Una "isla" es un grupo de celdas adyacentes entre sí, ya sea vertical u horizontalmente:
Aquí tenemos dos islas de 1: arriba a la izquierda y abajo a la derecha.
Una solución simple es hacer una primera pasada sobre toda la matriz y reemplazar los valores de 1 con un contador incremental de modo que al final cada 1 se reemplaza con su número de secuencia en el orden principal de la fila:
En el siguiente paso, cada valor se reemplaza por el mínimo entre él y los valores de sus vecinos:
Ahora podemos determinar fácilmente que tenemos dos islas.
La parte que queremos ejecutar en paralelo es el paso donde calculamos los mínimos. Sin entrar en demasiados detalles, cada hilo obtiene filas de manera intercalada y se basa en los valores calculados por el hilo que procesa la fila anterior. Por lo tanto, cada hilo debe retrasarse ligeramente con respecto al hilo que procesa la línea anterior, pero también debe mantenerse al día dentro de un tiempo razonable. En este documento, presento más detalles y una implementación . Tenga en cuenta el uso de
sleep(0)
que es más o menos el equivalente en C deyield
.En este caso
yield
se utilizó para forzar a cada hilo a hacer una pausa, pero dado que el proceso del hilo de la fila adyacente avanzaría muy rápidamente mientras tanto, una variable de condición resultaría una elección desastrosa.Como puede ver,
yield
es una optimización bastante fina. Usarlo en el lugar incorrecto, por ejemplo, esperar en una condición que rara vez cambia, causará un uso excesivo de la CPU.Perdón por el largo parloteo, espero haberme aclarado.
fuente
yield
cuando la condición no se cumple para dar a los otros subprocesos la oportunidad de continuar con el cálculo, en lugar de usar más alto primitivas de sincronización de nivel, ¿verdad?yield
.Sobre las diferencias entre
yield()
,interrupt()
yjoin()
- en general, no sólo en Java:Para Java específicamente, consulte
Unión:
¿Cómo usar Thread.join? (aquí en StackOverflow)
¿Cuándo unir hilos?
Flexible:
Interrumpiendo:
¿Es Thread.interrupt () malvado? (aquí en StackOverflow)
fuente
wait()
no es una combinación, se trata de un bloqueo en el objeto que el subproceso que realiza la llamada está intentando adquirir; espera hasta que otros liberen el bloqueo y el subproceso lo haya adquirido. Modifiqué mi respuesta en consecuencia.Primero, la descripción real es
Ahora, es muy probable que su hilo principal ejecute el ciclo cinco veces antes de que se ejecute el
run
método del nuevo hilo, por lo que todas las llamadas ayield
ocurrirán solo después de que se ejecute el ciclo en el hilo principal.join
detendrá el hilo actual hasta que el hilo con el que se llamajoin()
termine de ejecutarse.interrupt
interrumpirá el hilo al que se llama, provocando InterruptedException .yield
permite un cambio de contexto a otros subprocesos, por lo que este subproceso no consumirá todo el uso de CPU del proceso.fuente
SwitchToThread()
llamar es mejor que Sleep (0) y esto debería ser un error en Java :)No hay diferencias prácticas
Thread.yield()
entre las versiones de Java desde la 6 hasta la 9.TL; DR;
Conclusiones basadas en el código fuente de OpenJDK ( http://hg.openjdk.java.net/ ).
Si no se tiene en cuenta la compatibilidad con HotSpot de las sondas USDT (la información de seguimiento del sistema se describe en la guía dtrace ) y la propiedad JVM, el
ConvertYieldToSleep
código fuente deyield()
es casi el mismo. Vea la explicación a continuación.Java 9 :
Thread.yield()
llama al método específico del sistema operativoos::naked_yield()
:En Linux:
En Windows:
Java 8 y versiones anteriores:
Thread.yield()
llama al método específico del sistema operativoos::yield()
:En Linux:
En Windows:
Como puede ver,
Thread.yeald()
en Linux es idéntico para todas las versiones de Java.Veamos Windows
os::NakedYield()
de JDK 8:La diferencia entre Java 9 y Java 8 en la verificación adicional de la existencia del
SwitchToThread()
método de la API Win32 . El mismo código está presente para Java 6. Elcódigo fuente de
os::NakedYield()
en JDK 7 es ligeramente diferente pero tiene el mismo comportamiento:La comprobación adicional se ha eliminado debido a que el
SwitchToThread()
método está disponible desde Windows XP y Windows Server 2003 (consulte las notas de msdn ).fuente
Yield sugiere a la CPU que puede detener el subproceso actual y comenzar a ejecutar subprocesos con mayor prioridad. En otras palabras, asignar un valor de prioridad baja al hilo actual para dejar espacio para hilos más críticos.
NO, los dos producirán resultados diferentes. Sin un rendimiento (), una vez que el hilo toma el control, ejecutará el ciclo 'Ejecución interior' de una vez. Sin embargo, con un yield (), una vez que el subproceso obtiene el control, imprimirá la 'ejecución interna' una vez y luego entregará el control a otro subproceso, si lo hay. Si no hay ningún hilo pendiente, este hilo se reanudará nuevamente. Por lo tanto, cada vez que se ejecuta "Inside run", buscará otros subprocesos para ejecutar y, si no hay ningún subproceso disponible, el subproceso actual seguirá ejecutándose.
yield () es para dar espacio a otros subprocesos importantes, join () es para esperar a que otro subproceso complete su ejecución, e interrupt () es para interrumpir un subproceso actualmente en ejecución para hacer otra cosa.
fuente
Without a yield(), once the thread gets control it will execute the 'Inside run' loop in one go
? Por favor aclare.Thread.yield()
hace que el hilo pase del estado "En ejecución" al estado "Ejecutable". Nota: No hace que el hilo pase al estado "En espera".fuente
RUNNING
estado parajava.lang.Thread
instancias. Pero eso no excluye un estado nativo de "ejecución" para el subproceso nativo para el que unaThread
instancia es un proxy.Thread.yield ()
unirse()
fuente
El uso principal de yield () es poner en espera una aplicación de subprocesos múltiples.
todas estas diferencias de métodos son yield () pone el hilo en espera mientras se ejecuta otro hilo y regresa después de la finalización de ese hilo, join () reunirá el comienzo de los hilos ejecutándose hasta el final y de otro hilo para que se ejecute después de que ese hilo haya terminado, interrupt () detendrá la ejecución de un hilo por un tiempo.
fuente
yield
debería usarse.