Java multithreading (uno)
Como un punto de conocimiento muy importante en Java, todavía es necesario resumirlo aquí.
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 (debido a que el bloqueo está ocupado por otros hilos), 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 = 0; @Override public void run () {for (i = 0; i <100; i ++) {system.out.println (thread.currentThread (). GetName () + "" + i); }}} public class ThreadTest {public static void main (string [] args) {for (int i = 0; i <100; i ++) {System.out.println (Thread.CurrentThread (). getName () + "" + i); if (i == 30) {Thread myThread1 = new Mythread (); // Crear un nuevo hilo MyThread1 Este hilo ingresa al nuevo hilo de estado mythread2 = new MyThread (); // Crear un nuevo hilo MyThread2 Este hilo ingresa al nuevo estado mythread1.start (); // Llame al método Start () para hacer que el hilo ingrese el estado listo mythread2.start (); // llame al método Start () para que el subproceso ingrese al estado listo}}}}Como se muestra arriba, heredando la clase de subprocesos, un nuevo mythread de clase de hilo se define sobrescribiendo el método run (), donde el cuerpo del método del método run () representa la tarea que el hilo necesita 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.
Clase Myrunnable Implements runnable {private int i = 0; @Override public void run () {for (i = 0; i <100; i ++) {system.out.println (thread.currentThread (). GetName () + "" + i); }}} public class ThreadTest {public static void main (string [] args) {for (int i = 0; i <100; i ++) {System.out.println (Thread.CurrentThread (). getName () + "" + i); if (i == 30) {runnable myrunnable = new Myrunnable (); // Crear un objeto de clase de implementación Runnable Thread Thread1 = New Thread (MyRunnable); // Cree un nuevo hilo con Myrunnable como un hilo Target Thread Thread2 = New Thread (MyRunnable); Thread1.Start (); // Llame al método Start () para hacer que el subproceso ingrese el estado de estado listo. }}}} 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 = 0; i <100; i ++) {System.out.println (Thread.CurrentThread (). getName () + "" + i); if (i == 30) {runnable myrunnable = new Myrunnable (); Thread Thread = new MyThread (MyRunnable); Thread.Start (); }}}} class Myrunnable Implements runnable {private int i = 0; @Override public void run () {system.out.println ("en runrunnable run"); para (i = 0; i <100; i ++) {System.out.println (Thread.CurrentThread (). GetName () + "" + I); }}} La clase myThread extiende el hilo {private int i = 0; public mythread (runnable runnable) {super (runnable); } @Override public void run () {system.out.println ("en mythread run"); para (i = 0; i <100; i ++) {System.out.println (Thread.CurrentThread (). GetName () + "" + I); }}}Del mismo modo, lo mismo es cierto para crear hilos que implementan la interfaz runnable, la diferencia es que
1 hilo de hilo = nuevo 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.
interfaz pública 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:
@Override public void run () {if (target! = Null) {target.run (); }}Es decir, al ejecutar el método run () en la clase de subprocesos, primero determinará si el objetivo existe. 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 = 0; i <100; i ++) {System.out.println (Thread.CurrentThread (). GetName () + "" + i); if (i == 30) {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 el bucle ha sido ejecutado ..."); intente {int sum = ft.get (); // Obtenga el resultado devuelto por el método Call () en el nuevo hilo recién creado System.out.println ("sum =" + sum); } catch (InterruptedException e) {E.PrintStackTrace (); } catch (ExecutionException e) {E.PrintStackTrace (); }}} clase mycallable implementa llamable <integer> {private int i = 0; // A diferencia del método run (), el método call () tiene un valor de retorno @Override público entero llamado () {int sum = 0; for (; i <100; i ++) {System.out.println (Thread.CurrentThread (). GetName () + "" + I); suma += i; } suma 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 sirve 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 de 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 (); Hilo de hilo = nuevo hilo (myrunnable); for (int i = 0; i <100; i ++) {System.out.println (Thread.CurrentThread (). GetName () + "" + I); if (i == 30) {thread.start (); } if (i == 40) {myrunnable.stopThread (); }}}} clase Myrunnable implementos runnables {stop private boolean; @Override public void run () {for (int i = 0; i <100 &&! Stop; i ++) {system.out.println (thread.currentThread (). GetName () + "" + i); }} public void stopThread () {this.stop = true; }}Continuaremos ordenando artículos relacionados en el futuro. ¡Gracias por su apoyo para este sitio!
Serie de artículos:
Explicación de las instancias de Java Multi-Thread (I)
Explicación detallada de las instancias de Java Multi-Thread (ii)
Explicación detallada de las instancias de Java Multi-Thread (iii)