1. Hilos y procesos
1. ¿Cuál es la diferencia entre hilo y proceso:
Un hilo se refiere a una unidad de ejecución que puede ejecutar el código del programa durante la ejecución. En el idioma Java, los hilos tienen cuatro estados: ejecutar, listo, suspender y terminar.
Un proceso se refiere a un programa que se está ejecutando. Los hilos también se convierten en procesos livianos cuando tienen algo que hacer. Tienen la unidad más pequeña de ejecución del programa. Un proceso puede tener múltiples hilos. Cada hilo comparte el espacio de energía interno del programa (segmentos de código, segmentos de datos y espacio de almacenamiento de montón) y algunos recursos de nivel de proceso (como archivos abiertos), pero cada hilo tiene su propio espacio.
2. ¿Por qué usar el proceso múltiple ? <Br /> Existen principalmente los siguientes aspectos en el nivel del sistema operativo:
- El uso de múltiples subprocesos puede reducir el tiempo de respuesta del programa. Si una operación lleva mucho tiempo o está atascada en una larga espera, el programa no responderá a operaciones como el mouse y el teclado. Después de usar múltiples subprocesos, este hilo que consume mucho tiempo se puede asignar a un hilo separado para la ejecución, lo que hace que el programa sea mejor interactividad.
- La creación de subprocesos y la sobrecarga de cambio es menos costosa en comparación con los procesos, mientras que la lectura múltiple es muy eficiente en el intercambio de datos.
-Las computadoras multi-CPU o múltiples tienen la capacidad de ejecutar múltiples hilos. Si se utiliza un solo proceso, los recursos de la computadora no se reutilizarán, lo que dará como resultado una gran pérdida de recursos. El uso de la lectura múltiple en computadoras multi-CPU puede mejorar la utilización de la CPU.
- El uso de múltiples lecturas puede simplificar la estructura del programa y facilitar la comprensión y el mantenimiento.
2. Creación de hilos <Br /> generalmente hay tres métodos para la implementación de múltiples subprocesos, y los dos primeros son los métodos más utilizados:
1. Heredar la clase de subproceso y anular el método run ()
Thread es esencialmente una instancia que implementa la interfaz ejecutable. Cabe señalar que después de llamar al método Start (), no ejecuta un código multiproceso de inmediato, sino que hace que el hilo se ejecute. El sistema operativo determina el código de múltiples subprocesos.
Estos son los pasos principales:
(1) Defina la subclase de la clase de subprocesos y anula el método de ejecución de la clase. El cuerpo del método del método de ejecución representa la tarea que el hilo quiere completar. Por lo tanto, el método run () se llama cuerpo de ejecución.
(2) Cree una instancia de la subclase de hilo, es decir, cree un objeto de subproceso.
(3) Llame al método Start () del objeto de subproceso para iniciar el hilo.
Public Class TestThread extiende Thread {public void run () {System.out.println ("Hello World"); } public static void main (string [] args) {Thread mthread = new testThread (); mthread.start (); }} 2. Implemente la interfaz ejecutable e implementa el método run () de la interfaz
Estos son los pasos principales:
(1) Personalizar la clase e implementar la interfaz ejecutable e implementar el método run ().
(2) Cree una instancia de la subclase de subprocesos e instanciar el objeto de subproceso con el objeto que implementa la interfaz ejecutable como un parámetro.
(3) Llame al método Start () del hilo para iniciar el hilo.
Public Class TestRunnable Implements Runnable {public void run () {System.out.println ("Hello World"); }} clase pública testRunnable {public static void main (string [] args) {testRunnable mtestrunnable = new testRunnable (); Hilo mthread = new Thread (mtestrunnable); mthread.start (); }} 3. Implemente la interfaz invocatoria y anule el método de llamada ()
La interfaz invocatoria es en realidad una clase funcional en el marco del ejecutor. La interfaz invocatoria es similar a la interfaz Runnable, pero proporciona funciones más potentes que Runnable, que se manifiestan principalmente en los siguientes 3 puntos:
(1) Callable puede proporcionar un valor de retorno después de que se acepta la tarea, y Runnable no puede proporcionar esta función.
(2) El método de llamada () en Callable puede lanzar excepciones, mientras que el método Run () de Runnable no puede lanzar excepciones.
(3) Ejecutar llamable puede obtener un objeto futuro. El objeto futuro representa el resultado del cálculo de Ibrahimovic, y él proporciona un método para verificar si el cálculo se completa. Dado que el hilo pertenece a un modelo de cálculo asincrónico, es imposible obtener el valor de retorno de la función de otros hilos. En este caso, el futuro se puede usar para monitorear el método de llamada () cuando el hilo de destino llama al método de llamada (). Sin embargo, cuando se llama al método Future Get () para obtener el resultado, el hilo actual bloqueará y sabrá el resultado de retorno del método de llamada ().
public class testCallable {// Crear clase de subproces de clase estática pública mytestCallable implementos llamables {public string call () lanza excepción {retun "Hello World"; }} public static void main (string [] args) {mytestCallable mmytestCallable = new myTestCallable (); EjecutorService MexecutorService = Ejecutors.NeWSingLethreadPool (); Futuro mfuture = mexecutorservice.submit (mmytestcallable); intente {// esperando que el hilo finalice y devuelva el resultado System.out.println (mfuture.get ()); } catch (Exception e) {E.PrintStackTrace (); }}}El resultado de salida del programa anterior es: Hello World
Entre estos tres métodos, generalmente se recomienda implementar la interfaz ejecutable. La razón es: Primero, la clase de subprocesos define una variedad de métodos que pueden reescribirse mediante clases derivadas, pero solo se debe reescribir el método Run (), que realiza la función principal de este hilo, que también es el método requerido para implementar la interfaz ejecutable. En segundo lugar, una clase debe ser heredada cuando necesiten ser fortalecidas o modificadas. Por lo tanto, si no es necesario anular otros métodos de la clase de subprocesos, es mejor implementar la interfaz ejecutable en este caso.
3. Interrupción de hilo <Br /> El hilo terminará cuando el método Run () del hilo ejecute la última declaración en el cuerpo del método y devuelva ejecutando la declaración de retorno, o cuando no se captura una excepción que no se captura en el método. Hubo un método de parada en versiones anteriores de Java, que otros hilos podían llamar para terminar el hilo, pero este método ahora se ha desaprobado.
El método de interrupción se puede utilizar para solicitar la terminación del hilo. Cuando un hilo llama al método de interrupción, se establecerá el estado de interrupción del hilo. Esta es la bandera booleana que ningún hilo tiene. Cada hilo debe verificar esta bandera de vez en cuando para determinar si el hilo está interrumpido.
Para averiguar si el hilo está configurado, puede llamar a thread.currentThread (). Isinterrupted ()::
while (! Thread.CurrentThread (). isinterrupted ()) {do algo} Sin embargo, si se bloquea un hilo, el estado de interrupción no se puede detectar. Aquí es donde se genera la Excepción InterruptedEx. Cuando se llama a un método de interrupción en un hilo bloqueado (llamado sueño o espera). La llamada de bloqueo será interrumpida por InterruptedException.
Si se llama al método de sueño (u otro método interrumpible) después de cada iteración, la detección ISInterrupted es innecesaria e inútil. Si se llama al método de sueño cuando se establece el estado de interrupción, no dormirá, pero despejará el estado y lanzará una Excepción InterruptedEx. Entonces, si llama a dormir en un bucle, no detecte el estado de la interrupción, simplemente atrapa la EXPERTAMIENTA DE INTERRUPTEDEX.
En muchos códigos publicados, encontrará que InterruptedException se suprime a un nivel muy bajo:
void myTask () {... try {sleep (50)} Catch (InterruptedException e) {...}}No hagas esto. Si no cree que haya algún beneficio en una captura, hay dos opciones razonables:
Llame a Thread.CurrentThread (). Interrup () en captura para establecer el estado de interrupción. Las personas que llaman pueden detectarlo. Una mejor opción es usar Show InterruptedException para marcar su método, sin usar bloques de instrucción de prueba para capturar la completa. De esta manera, la persona que llama puede ver esta excepción:
void myTask () Throw InterruptedException {Sleep (50)}4. El estado del hilo
(1). Nuevo estado (nuevo): se crea un nuevo objeto de subproceso.
(2). Estado Ready (runnable): después de que se crea el objeto de subproceso, otros hilos llaman al método Start () del objeto. El hilo en este estado se encuentra en el grupo de hilos ejecutables y se vuelve ejecutable, esperando obtener los derechos de uso de la CPU.
(3). Estado en ejecución: el hilo en el estado listo adquiere la CPU y ejecuta el código del programa.
(4). Estado bloqueado: el estado bloqueado significa que el hilo renuncia a los derechos de uso de la CPU por alguna razón y deja de funcionar temporalmente. No es hasta que el hilo ingresa al estado listo que tiene la oportunidad de ir al estado en funcionamiento. Hay tres tipos de bloqueo:
- Esperando bloquear: el hilo en ejecución ejecuta el método Wait (), y el JVM colocará el hilo en la piscina de espera.
- Bloqueo sincrónico: cuando el hilo en ejecución adquiere el bloqueo de sincronización del objeto, si el bloqueo de sincronización está ocupado por otros hilos, el JVM colocará el hilo en la piscina de bloqueo.
- Otro bloqueo: Cuando un hilo en ejecución ejecuta el método sleep () o unir (), o emite una solicitud de E/S, el JVM establecerá el hilo en un estado de bloqueo. 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.
(5). Estado muerto: 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.
5. Prioridad de hilo y hilo de demonio
1. Prioridad del hilo
En Java, cada hilo tiene una prioridad y, por defecto, un hilo hereda la prioridad de su clase principal. Puede usar el método SetPriority para aumentar o disminuir cualquier prioridad de hilo. La prioridad se puede establecer en cualquier valor entre min_priority (definido como 1 en la clase de hilo) y max_priority (definido como 10 en la clase de hilo). La prioridad predeterminada de los subprocesos es Norm_priority (definido como 5 en la clase de subprocesos).
Trate de no confiar en la prioridad. Si realmente quieres usarlo, debes evitar un error común que cometen los principiantes. Si varios hilos de alta prioridad no entran en el estado inactivo, los hilos de baja prioridad nunca se pueden ejecutar. Cada vez que el planificador decide ejecutar un nuevo hilo, primero selecciona entre los hilos con prioridad, aunque esto de hambre de manera completamente de hilo de baja prioridad.
2. Hilo de demonio
Llamar setdaemon (verdadero); Convierte el hilo en un hilo de demonio. El único propósito de los hilos de demonio es proporcionar servicios a otros hilos. El hilo de tiempo es un ejemplo. Envía señales a otros subprocesos regularmente o borra los hilos obsoletos que le indican los elementos de caché. Cuando solo quedan hilos de demonio, la máquina virtual sale, porque si solo quedan hilos de demonio, no hay necesidad de continuar ejecutando el programa.
Además, la recolección de basura de JVM, la gestión de la memoria y otros hilos son hilos de demonio. Además, al hacer aplicaciones de bases de datos, el grupo de conexión de la base de datos utilizada también contiene muchos subprocesos de fondo, monitoreando el número de conexiones, tiempo de tiempo de espera, estado, etc.
Lo anterior se trata de la definición de hilo, el estado y las propiedades de Java Multithreading. Espero que sea útil para el aprendizaje de todos.