La lectura múltiple es un punto de conocimiento muy importante en Java. Aquí, el editor le resume Java Thread multithreading, lo cual es muy útil. Espero que puedas dominarlo.
1. El ciclo de vida de un hilo y los cinco estados básicos
Con respecto al ciclo de vida de los hilos en Java, veamos primero la siguiente imagen clásica:
La figura anterior básicamente cubre los puntos de conocimiento importantes del subproceso múltiple en Java. Una vez que domine los puntos de conocimiento en la figura anterior, básicamente dominará el múltiple subproceso en Java. Principalmente incluyendo:
Los hilos de Java tienen cinco estados básicos
Nuevo estado (nuevo): cuando se crea un par de objetos de hilo, ingresa a un nuevo estado, como: hilo t = nuevo mythread ();
Estado Ready (Runnable): cuando el método Start () del objeto de subproceso (t.start ();), el hilo ingresa al estado listo. Un hilo en el estado listo solo significa que el hilo está listo y está esperando que la CPU programen la ejecución en cualquier momento, no que el hilo se ejecute inmediatamente después de que se ejecute t.Start ();
Estado en ejecución: cuando la CPU comienza a programar hilos en el estado listo, el hilo se puede ejecutar verdaderamente, es decir, ingresa al estado en ejecución. Nota: El estado listo es la única entrada al estado en ejecución, es decir, si un hilo quiere ingresar al estado en ejecución para ejecutar, primero debe estar en el estado listo;
Estado bloqueado: por alguna razón, un hilo en el estado en ejecución da temporalmente el uso de la CPU y detiene la ejecución. En este momento, ingresa al estado de bloqueo. No tendrá la oportunidad de ser llamado nuevamente por la CPU para ingresar al estado en ejecución.
Según las razones para el bloqueo, los estados de bloqueo se pueden dividir en tres tipos:
1. Esperando el bloqueo: el hilo en el estado en ejecución ejecuta el método Wait () para que el hilo ingrese al estado de bloqueo;
2. Bloqueo sincronizado: el hilo no puede adquirir el bloqueo de sincronización sincronizado (porque el bloqueo está ocupado por otros hilos) e ingresará al estado de bloqueo sincronizado;
3. Otro bloqueo: el hilo ingresará a un estado de bloqueo llamando a dormir () o unirse () del hilo o emitir una solicitud de E/S. Cuando el estado de sueño () se agotó, unirse () esperó a que el hilo termine o se agotara, o se completó el procesamiento de E/S, el hilo volvió a ingresar al estado listo.
Dead: el hilo ha terminado de ejecutar o salir del método Run () debido a una excepción, y el hilo finaliza su ciclo de vida.
2. Creación e inicio de Java Multithreads
Hay tres formas básicas de creación de hilos en Java
1. Heredar la clase de hilo y anular el método run () de la clase.
La clase MyThread extiende el hilo {private int i =; @OverridePublic Void run () {for (i =; i <; i ++) {System.out.println (Thread.CurrentThread (). getName ()+""+i);}}} public class ThreadTest {public estatic estatic bain (string []) {System.out.println (Thread.CurrentThread (). GetName () + "" + i); if (i ==) {Thread myThread = new MyThread (); // Crear un nuevo hilo mythread Este hilo ingresa al nuevo hilo de estado mythread = new MyThread (); // Crear un nuevo hilo mythread Este hilo ingresa al nuevo estado mythread.start (); // Llame al método Start () para que el hilo ingrese el estado listo mythread.start (); // llame al método Start () para que el subproceso ingrese al estado listo}}}} Como se muestra arriba, herede la clase de hilo y anule el método Run (), se define un nuevo mythread de la clase de hilo, donde el cuerpo del método del método run () representa la tarea que el hilo debe completar, y se llama cuerpo de ejecución del hilo. Al crear este objeto de clase de hilo, se crea un nuevo hilo y ingresa al nuevo estado de hilo. Al llamar al método Start () referenciado por el objeto de subproceso, el hilo ingresa al estado listo. En este momento, el hilo no puede ejecutarse de inmediato, dependiendo de la sincronización de programación de la CPU.
2. Implemente la interfaz ejecutable y anula el método run () de la interfaz. El método run () también es un cuerpo de ejecución de hilos, crea una instancia de la clase de implementación Runnable y usa esta instancia como el objetivo de la clase de subprocesos para crear un objeto de subproceso. El objeto de hilo es el objeto de hilo real.
class myrunnable implements runnable {private int i =; @OverridePublic void run () {for (i =; i <; i ++) {system.out.println (thread.currentThread (). getName ()+""+i);}}} public class ThreadTest {public Void Public static main (string []) {System.out.println (Thread.CurrentThread (). GetName () + "" + i); if (i ==) {runnable myrunnable = new Myrunnable (); // Crear un objeto de clase de implementación Runnable Thread Thread = New Thread (MyRunnable); // use Myrunnable como un objetivo de subproceso para crear un nuevo hilo de hilo hilo = nuevo hilo (myrunnable); thread.start (); // Llame al método Start () para que el subproceso ingrese el estado listo thread.start ();}}}} Creo que todos están familiarizados con las dos formas anteriores de crear nuevos hilos. Entonces, ¿cuál es la relación entre Thread y Runnable? Primero veamos el siguiente ejemplo.
public class ThreadTest {public static void main (string [] args) {for (int i =; i <; i ++) {system.out.println (thread.currentThread (). getName () + "" + i); if (i ==) {runnable myrunNable = new MyrunNable (); Thread Threat = new Thread = new three Mythread (myrunnable); thread.start ();}}}} class myrunnable implements runnable {private int i =; @OverridePublic Void run () {System.Println ("en MyRunnable Run"); for (i =; i <; i ++) {System.Println (shift.currErt ();); + i);}}} class myThread extiende el hilo {private int i =; public mythread (runnable runnable) {super (runnable);}@overridePublic void void run () {system.out.println ("en mythread run"); for (i =; i <; i ++) {system.println (shift.current (). + i);}}} Del mismo modo, lo mismo es cierto para crear hilos que implementan la interfaz runnable, la diferencia es que
Thread Thread = new MyThread (MyRunnable);
Entonces, ¿puede este método crear con éxito un nuevo hilo? La respuesta es sí. En cuanto al cuerpo de ejecución de hilos en este momento, ¿el método run () en la interfaz myrunnable o el método run () en la clase mythread? A través de la salida, sabemos que el cuerpo de ejecución de subprocesos es el método run () en la clase mythread. De hecho, la razón es muy simple, porque la clase de subprocesos en sí también implementa la interfaz ejecutable, y el método run () se define primero en la interfaz ejecutable.
Public Interface Runnable {public abstract void run ();} Echemos un vistazo a la implementación del método run () en la interfaz ejecutable en la clase de subprocesos:
@OverridePublic Void run () {if (Target! = NULL) {Target.run ();}} Es decir, al ejecutar el método run () en la clase de hilo, el método run () en el destino se determinará primero. Si existe, se ejecuta el método run () en el destino, es decir, el método run () en la clase que implementa la interfaz ejecutable y sobrescribe el método run (). Sin embargo, en las columnas dadas anteriormente, debido a la existencia de polimorfismo, el método run () en la clase de subproceso no se ejecuta en absoluto, pero el tipo de tiempo de ejecución, es decir, el método run () en la clase mythread se ejecuta directamente.
3. Cree hilos utilizando interfaces llamables y futuras. Específicamente, crea una clase de implementación para la interfaz invocable e implementa el método Clall (). Y use la clase FUTURETASK para envolver el objeto de clase de implementación llamable y use este objeto FuturetAk como el objetivo del objeto de subproceso para crear un hilo.
Parece un poco complicado, pero será claro si mira un ejemplo directamente.
public class Threadtest {public static void main (string [] args) {llamable <integer> mycallable = new myCallable (); // Crear objeto myCallable FutureTask <integer> ft = new FuturetAk <integer> (myCallable); // Use FuturetAk para envolver el objeto MyCallable para (int i =; i <; i ++) {System.out.println (Thread.CurrentThread (). GetName () + "" + i); if (i ==) {Thread Thread = New Thread (ft); // El objeto FuturetASk crea un nuevo hilo como objetivo del objeto de subproceso thread.start (); // El hilo ingresa al estado listo}} system.out.println ("El hilo principal para la ejecución de bucle completada ..."); intente {int sum = ft.get (); // Obtenga el resultado devuelto por el método de llamada () en el nuevo hilo recién creado System.out.println ("sum =" + sum);} capt (interruptedException e) {E.PrintStActAtRace ();} Catch (EjecutionException e) {E.PrintStace ();}}} Clase MyCALLable Implements Callable <Steger> {private INT IT =/////////////////////////////////[) Run () () Run () () Run () () Run {); El método, el método de llamada () tiene el valor de retorno @OverridePublic Integer Call () {int sum =; for (; i <; i ++) {System.out.println (Thread.CurrentThread (). GetName () +"" +i); sum += i;} Sume de retorno;}} En primer lugar, descubrimos que al implementar la interfaz de llamada, el método run () ya no es el método run (), sino el método call (). ¡Este método de llamada () es el cuerpo de ejecución de hilos y también tiene un valor de retorno! Al crear un nuevo hilo, el objeto MyCallable se envuelve a través de FuturetAk y también se usa como objetivo para el objeto de subproceso. Luego mire la definición de la clase FuturetAk:
Public Class FutUreTask <V> implementa RunnableFuture <V> {// ....} Public Interface RunnableFuture <V> extiende Runnable, Future <V> {void run ();} Por lo tanto, descubrimos que la clase FuturetAk en realidad implementa interfaces ejecutables y futuras, lo que hace que tenga las características duales del futuro y la ejecución ejecutable. A través de la función Runnable, se puede usar como objetivo del objeto de subproceso, y la función futura le permite obtener el valor de retorno del método Call () en el hilo recién creado.
Después de ejecutar este programa, encontramos que Sum = 4950 es siempre el último resultado. "El hilo principal para el bucle se ha ejecutado ..." Es probable que se genere en el medio del bucle de hilo infantil. Desde el mecanismo de programación de hilo de la CPU, sabemos que no hay problema con el momento de salida de "El hilo principal para el bucle se ha ejecutado ...", entonces, ¿por qué se emitirá SUM = 4950 para siempre?
La razón es que cuando el método de llamada del hilo infantil () se obtiene a través del método ft.get (), cuando el método del hilo infantil aún no se ha ejecutado, el método ft.get () bloqueará hasta que el método de llamada () se ejecute antes de que se pueda obtener el valor de retorno.
Lo anterior explica principalmente tres métodos comunes de creación de hilos. Para el inicio de los subprocesos, todos se denominan método Start () del objeto de subproceso. Es importante tener en cuenta que el método Start () no se puede llamar dos veces en el mismo objeto de subproceso.
Iii. Estado de listos, ejecutivos y de muerte de Java múltiple
El estado listo se convierte al estado en ejecución: cuando este hilo obtiene el recurso del procesador;
El estado en ejecución se convierte al estado listo: cuando este hilo llama activamente el método de rendimiento () o pierde los recursos del procesador durante la ejecución.
El estado en ejecución se convierte en el estado muerto: cuando se completa el cuerpo de ejecución del hilo o se produce una excepción.
Cabe señalar aquí que cuando se llama el método de rendimiento () del hilo, las transiciones de hilo del estado en ejecución al estado listo, pero qué hilo en el estado listo en la CPU está programado tiene una cierta aleatoriedad. Por lo tanto, puede ocurrir que después de un subproceso llame al método de rendimiento (), la CPU aún programa el hilo A.
Debido a las necesidades comerciales reales, a menudo se encuentra que un hilo debe terminar en una oportunidad específica para que ingrese a un estado muerto. El método más común en la actualidad es establecer una variable booleana, y cuando se cumplan las condiciones, el cuerpo de ejecución de hilos se ejecutará rápidamente. como:
public class ThreadTest {public static void main (string [] args) {myrunnable myrunnable = new MyRunnable (); Thread Thread = New Thread (MyRunnable); for (int i =; i <; i ++) {System.out.println (Thread.CurrentThread (). GetName () + " +" + i); if (i ==) {thread.start ();} if (i ==) {myrunnable.stopThread ();}}}} class myrunnable implements runnable {private boolean stop; @OverridePublic Void run () {for (int i =; i <&&! + i);}} public void stopThread () {this.stop = true;}}Lo anterior es un análisis exhaustivo de Java Thread Multi-Threading que el editor le presentó. Espero que te sea útil. Si tiene alguna pregunta, déjame un mensaje y el editor le responderá a tiempo. ¡Muchas gracias por su apoyo al sitio web de Wulin.com!