Ali p9 le enseña a comprender el principio de subprocesos múltiples de Java en tres minutos

Prólogo El
grupo de subprocesos, de ahí que el nombre lo sugiera, es un grupo para almacenar subprocesos. Para decirlo de manera más académica, es una colección de recursos de subprocesos. ¿Por qué existe un concepto de grupo de subprocesos? Piénselo antes, cuando todos necesitamos subprocesos, creamos uno directamente de forma manual, y luego no nos importa después de ejecutar la tarea. El subproceso es una herramienta o portador para que realicemos tareas asincrónicas. No pagamos mucha atención al subproceso en sí. El impacto del ciclo de vida en el sistema o el medio ambiente, y solo se centra en la salida de los resultados de la ejecución de tareas de subprocesos múltiples, y luego se logra el objetivo, pero el mantenimiento y el monitoreo de los recursos de subprocesos se ignoran realmente. Con el uso de una gran cantidad de recursos de subprocesos múltiples en sistemas a gran escala, la falta de atención, mantenimiento y gestión de subprocesos múltiples ha ampliado gradualmente su impacto en la ocupación de recursos y la reducción del rendimiento, lo que despertó el pensamiento de las personas.

  1. Elemento de lista

La creación y destrucción de subprocesos múltiples ocupa una gran proporción en el ciclo de vida de subprocesos múltiples. Esta parte realmente consume recursos y rendimiento. Si los subprocesos se utilizan para realizar tareas simples, el costo de mantenimiento de los subprocesos ha superado los beneficios de la tarea. ejecución. No vale la pena perder, por lo que se crea un grupo de subprocesos. Mediante el uso de grupos de subprocesos, se puede controlar el ciclo de vida de los subprocesos, y los subprocesos se pueden obtener y reutilizar fácilmente y se puede evitar la sobrecarga de rendimiento adicional causada por la creación y destrucción frecuentes de subprocesos. Este es probablemente el trasfondo y la intención original de la introducción de grupos de subprocesos.

1. Método de creación de múltiples subprocesos
1.1 Heredar la clase Thread para crear la clase de subprocesos
1. Pasos de implementación
Defina una subclase que herede la clase Thread y anule el método run () de esta clase;

Cree una instancia de la subclase Thread, es decir, cree un objeto thread;

Llame al método start () del objeto hilo para iniciar el hilo.

2. 核心 代码
`class SomeThead extiende Thraad {public void run () {// haz algo aquí
}
}

public static void main (String [] args) {SomeThread oneThread = new SomeThread ();
// 启动 线程
oneThread.start (); } `

1.2 Implementar la interfaz Runnable para crear una clase de subproceso
1. Pasos de implementación
Definir la clase de implementación de la interfaz Runnable y reescribir el método run () de la interfaz;

Cree una instancia de la clase de implementación Runnable y utilice esta instancia como el objeto de destino de Thread, es decir, el objeto Thread es el objeto de hilo real.

2. 核心 代码
clase SomeRunnable implementa Runnable {public void run () {// hacer algo aquí}} Runnable oneRunnable = new SomeRunnable (); Subproceso oneThread = nuevo subproceso (oneRunnable); oneThread.start ();

1.3 Crear un hilo a través de Callable y Future
1. Pasos de implementación
Crear una clase de implementación de la interfaz Callable e implementar el método call () El método modificado será el cuerpo de ejecución del hilo y tendrá un valor de retorno.

Cree una instancia de la clase de implementación Callable y use la clase FutrueTask para envolver el objeto Callable. El objeto FutureTask encapsula el valor de retorno del método call () del objeto Callable

Utilice el objeto FutureTask como destino del objeto Thread para crear e iniciar un nuevo hilo

Llame al método get () del objeto FutureTask para obtener el valor de retorno después de que finalice la ejecución del subproceso secundario.

2. Código principal
`// 1. Cree la clase de implementación de la interfaz invocable e implemente el método call () public class SomeCallable01 implementa Callable {@Override public Integer call () throws Exception {int i = 0; for (; i < 10; i ++) {System.out.println (Thread.currentThread (). GetName () + "" + i);} return i;}

public static void main (String [] args) { // 2. Cree una instancia de la clase de implementación invocable SomeCallable01 ctt = new SomeCallable01 ();

//3.使用FutrueTask类进行包装Callable对象,FutureTask对象封装了Callable对象的call()方法的返回值
FutureTask<Integer> ft = new FutureTask<>(ctt);

//开启ft线程
for(int i = 0;i < 21;i++)
{
    System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);
    if(i==20)//i为20的时候创建ft线程
    {
    	//4.使用FutureTask对象作为Thread对象的target创建并启动新线程
        new Thread(ft,"有返回值的线程FutureTask").start();
    }
}

//ft线程结束时,获取返回值
try
{	
	//5.调用FutureTask对象的get()方法获取子线程执行结束后的返回值。
    System.out.println("子线程的返回值:"+ft.get());//get()方法会阻塞,直到子线程执行结束才返回
} catch (InterruptedException e)
{
    e.printStackTrace();
} catch (ExecutionException e)
{
    e.printStackTrace();
}

}
Copiar código
} `

En segundo lugar, la diferencia entre las formas de crear subprocesos
1. Utilice la clase Thread heredada para crear varios subprocesos
1) Ventajas Es
simple de escribir. Si necesita acceder al subproceso actual, no necesita usar Thread.currentThread () método. Puede usar esto directamente para obtener el hilo actual.

2) Desventajas La
clase de subproceso ha heredado la clase de subproceso, por lo que ya no puede heredar de otras clases principales. (Existen limitaciones de herencia única)

Al crear varios subprocesos, cada tarea tiene variables miembro que no se comparten, y se debe agregar estática para lograr compartir

2. Utilice el método de implementación de la clase Runnable para crear subprocesos múltiples
1) Ventajas
Evita las limitaciones de la herencia única Varios subprocesos pueden compartir un objeto de destino, lo cual es muy adecuado para que los subprocesos múltiples procesen el mismo recurso.

2) Las desventajas son
más complicadas, el acceso al hilo debe usar el método Thread.currentThread (), sin valor de retorno.

3. Utilice el método de implementación de la interfaz invocable para crear varios subprocesos
1) Ventajas Tiene
un valor de retorno, evita las limitaciones de la herencia única y varios subprocesos pueden compartir un objeto de destino, lo que es muy adecuado para el procesamiento de subprocesos múltiples del mismo recurso.

2) Las desventajas son
más complicadas y debe usar el método Thread.currentThread () para acceder al hilo

4. La diferencia entre Runnable y Callable
1) El método invocable estipula (anulación) es call (), el método Runnable estipula (anulación) es run ().

2) Las tareas invocables pueden devolver valores después de la ejecución, pero las tareas ejecutables no pueden devolver valores.

3) El método de llamada puede generar excepciones, pero el método de ejecución no.

4) Ejecute la tarea invocable para obtener un objeto Future, que representa el resultado del cálculo asincrónico. Proporciona un método para comprobar si el cálculo está completo, esperar a que se complete y recuperar el resultado del cálculo. A través del objeto Future, puede comprender la ejecución de la tarea, cancelar la ejecución de la tarea y obtener el resultado de la ejecución future.get ().

3.
Programación de múltiples subprocesos 3.1. Estrategia de programación Intervalo de
tiempo: la programación de subprocesos adopta la rotación de intervalo de tiempo. Tipo preventivo: el subproceso de alta prioridad se apropia de la CPU

3.2. Método de programación Java
1) Para que los subprocesos de la misma prioridad formen una cola de primero en entrar, primero en salir (primero en llegar, primero en servirse), utilice la estrategia de intervalo de tiempo

2) Para alta prioridad, use la estrategia preventiva de programación de prioridades

3.3, el
nivel de prioridad del hilo :

PRIORIDAD_MÁX: 10

PRIORIDAD_MÍN: 1

NORM_PRIORIDAD: 5

método:

`getPriority (): devuelve la prioridad del hilo

setPriority (int newPriority): Cambia la prioridad del hilo`

Observaciones:

Los subprocesos de alta prioridad deben prevalecer sobre los derechos de ejecución de CPU de los subprocesos de baja prioridad. Pero solo en términos de probabilidad, es más probable que se ejecuten los subprocesos de alta prioridad. No significa que solo se ejecuten los subprocesos de alta prioridad antes de que se ejecuten los subprocesos de baja prioridad.

4. Gestión de estado multiproceso
4.1 Thread sleep-sleep
1) Descripción general
Si necesitamos pausar el subproceso que se está ejecutando actualmente durante un período de tiempo y entrar en el estado de bloqueo, podemos llamar al método de suspensión de Thread.

2) Método de suspensión de subprocesos
Ponga el subproceso en ejecución en suspensión dentro del número especificado de milisegundos:

sleep (long millis) Duerme el subproceso en ejecución dentro del número especificado de milisegundos más el número especificado de nanosegundos:

dormir (long millis , int nanos)

3) La implementación del código
sleep es un método estático, es mejor no llamarlo con el objeto de instancia de Thread, porque duerme el hilo que se está ejecutando actualmente, no el objeto del hilo que lo llama. Solo es válido para el hilo objeto en el estado de ejecución.

`public class SynTest {public static void main (String [] args) {new Thread (new CountDown (),“ 倒计时 ”) .start (); }}

la clase CountDown implementa Runnable {int time = 10; public void run () {while (true) {if (time> = 0) {System.out.println (Thread.currentThread (). getName () + “:” + time–); intente {Thread.sleep (1000); // 睡眠 时间 为 1 秒} catch (InterruptedException e) {e.printStackTrace (); }}}}} `

4) Comentarios
La programación de subprocesos de Java es el núcleo del subproceso múltiple de Java. Sólo una buena programación puede dar pleno rendimiento al rendimiento del sistema y mejorar la eficiencia de ejecución del programa. Pero no importa cómo el programador escriba el horario, solo puede afectar el orden de ejecución del hilo en la mayor medida posible, pero no puede lograr un control preciso. Porque después de usar el método de suspensión, el subproceso ingresa al estado de bloqueo, y solo cuando finaliza el tiempo de suspensión, volverá a ingresar al estado listo y el estado listo ingresará al estado de ejecución, que es controlado por el sistema, y ​​nosotros no puede interferir con precisión con él. Por lo tanto, si llama a Thread.sleep (1000) para hacer que el hilo duerma durante 1 segundo, el resultado puede ser superior a 1 segundo.

4.2. Concesión de subprocesos-rendimiento
1) Descripción general El
método yield () es similar al método sleep (). También es un método estático proporcionado por la clase Thread. También puede pausar el subproceso que se está ejecutando actualmente y ceder recursos de la CPU a otros Hilo. Pero a diferencia del método sleep (), no ingresa al estado de bloqueo, sino al estado listo. El método yield () solo hace que el hilo actual se detenga, vuelva a ingresar al grupo de hilos listo y deje que el programador de hilos del sistema vuelva a programar. Es muy posible que esta situación: cuando un hilo llama al método yield (), el programador de hilos lo programa de nuevo para entrar en el estado de ejecución para su ejecución.

De hecho, cuando un subproceso llama al método yield () para suspender, la prioridad es la misma que la del subproceso actual, o un subproceso con una prioridad más alta que el estado listo del subproceso actual es más probable que tenga una oportunidad de ejecución. Por supuesto, es posible, porque es imposible para nosotros interferir con precisión con el hilo de programación de la CPU.

2) Implementación de código
public class Test1 { public static void main (String [] args) throws InterruptedException { new MyThread ("nivel bajo", 1) .start (); new MyThread ("intermedio", 5) .start (); new MyThread ("Avanzado", 10) .start (); } }





class MyThread extiende Thread { public MyThread (String name, int pro) { super (name); // Establece el nombre del hilo this.setPriority (pro); // Establece la prioridad }



@Override  
public void run() {  
    for (int i = 0; i < 30; i++) {  
        System.out.println(this.getName() + "线程第" + i + "次执行!");  
        if (i % 5 == 0)  
            Thread.yield();  
    }  
}  

}
Copiar código
3) La diferencia entre suspensión y rendimiento
①Después de que el método de suspensión suspende el hilo actual, entrará en el estado de bloqueo. Solo cuando se acabe el tiempo de suspensión, entrará en el estado listo. Una vez que se llama al método de rendimiento, ingresa directamente al estado listo, por lo que puede ingresar al estado listo y programarse para el estado de ejecución.

②La declaración del método de suspensión arroja una InterruptedException, por lo que al llamar al método de suspensión, la excepción debe detectarse o la declaración de visualización arroja la excepción. El método de rendimiento no declara que se lanza una excepción de tarea.

③ El método de suspensión tiene una mejor portabilidad que el método de rendimiento y, por lo general, no se basa en el método de rendimiento para controlar la ejecución de subprocesos simultáneos.

4.3. Fusión de subprocesos: unión
1) Descripción general
El significado de la fusión de subprocesos es fusionar los subprocesos de varios subprocesos paralelos en un solo subproceso para su ejecución. El escenario de la aplicación es cuando un subproceso debe esperar a que se ejecute otro subproceso antes de que pueda ejecutarse, el La clase Thread proporciona El método de unión se utiliza para completar esta función. Tenga en cuenta que no es un método estático.

en breve:

Cuando el subproceso B ejecuta el método .join () del subproceso A, el subproceso B esperará y el subproceso B se ejecutará cuando finalice el subproceso A. join se puede utilizar para unir subprocesos temporalmente para su ejecución.

2) Método de combinación de subprocesos
Tiene tres métodos sobrecargados:

El subproceso actual espera a que se una al subproceso y espera a que termine el subproceso.

unión vacía ()

El tiempo más largo que el subproceso actual espera a que termine el subproceso es milisegundos.

Si el subproceso no se ejecuta dentro de milisegundos, entonces el subproceso actual entra en el estado listo y espera la programación de la CPU nuevamente

unión vacía (milisegundos largos)

El tiempo de espera más largo para que termine este hilo es milisegundos + nanos

Nanosegundos. Si el subproceso no se ejecuta dentro del tiempo de milisegundos, entonces el subproceso actual entra en el estado listo y espera la programación de la CPU nuevamente

void join (long millis, int nanos)

3) Implementación de código
public static void main (String [] args) throws InterruptedException { yieldDemo ms = new yieldDemo (); Thread t1 = new Thread (ms, "Zhang San queda después de comer"); Thread t2 = new Thread (ms , "Li Si se fue después de comer"); Thread t3 = new Thread (ms, "Wang Wu se fue después de comer"); t1.start (); t1.join ();





    t2.start();
    t3.start();
    System.out.println( "主线程");
}`

Thread t = new Thread (() -> { try { Thread.sleep (1000); } catch (InterruptedException e) { e.printStackTrace (); } r = 10; });






t.start ();
// Deja que el hilo principal se bloquee y espera a que se ejecute el hilo t antes de continuar
// Elimina la línea, el resultado de la ejecución es 0, más el resultado de la ejecución de la línea es 10
t.join ();
log.info ("r: {}”, r);

// Ejecutar resultado
13: 09: 13.892 [principal] INFO thread.TestJoin-r: 10
Copie el código
4.4, establezca la prioridad del hilo
1) Descripción general
Cada hilo tiene un atributo de prioridad cuando se ejecuta, el hilo con alta prioridad Puede obtener más ejecución oportunidades, mientras que los subprocesos con baja prioridad obtienen menos oportunidades de ejecución. De manera similar a la suspensión de subprocesos, la prioridad de subprocesos aún no puede garantizar el orden de ejecución de los subprocesos. Sin embargo, los subprocesos con alta prioridad tienen una mayor probabilidad de adquirir recursos de CPU, y los subprocesos con baja prioridad no están exentos de la oportunidad de ejecutarse.

La prioridad predeterminada de cada hilo tiene la misma prioridad que el hilo principal que lo creó. Por defecto, el hilo principal tiene prioridad normal.

2) Métodos de prioridad que involucran La
clase Thread proporciona los métodos setPriority (int newPriority) y getPriority () para establecer y devolver la prioridad de un hilo especificado. El parámetro del método setPriority es un número entero, que va de 1 a · 0. Puede usar las tres constantes estáticas proporcionadas por la clase Thread:

MAX_PRIORITY = 10 MIN_PRIORITY = 1 NORM_PRIORITY = 5

3) Implementación de código
public class Test1 { public static void main (String [] args) throws InterruptedException { new MyThread ("nivel alto", 10) .start (); new MyThread ("nivel bajo", 1) .start () ; } }




class MyThread extends Thread {  
    public MyThread(String name,int pro) {  
        super(name);//设置线程的名称  
        setPriority(pro);//设置线程的优先级  
    }  
    @Override  
    public void run() {  
        for (int i = 0; i < 100; i++) {  
            System.out.println(this.getName() + "线程第" + i + "次执行!");  
        }  
    }  
}

Copiar código
4) Comentarios
Aunque Java proporciona 10 niveles de prioridad, estos niveles de prioridad requieren el soporte del sistema operativo. La prioridad de los diferentes sistemas operativos no es la misma y no se corresponde bien con los 10 niveles de prioridad de Java. Por lo tanto, debemos usar MAX_PRIORITY, MIN_PRIORITY y NORM_PRIORITY tres constantes estáticas para establecer la prioridad, a fin de garantizar la mejor portabilidad del programa.

4.5 Subprocesos de fondo (demonio)
1) Descripción general El
uso de subprocesos de demonio es raro, pero no son inútiles Por ejemplo, subprocesos como la recolección de basura y la gestión de memoria de JVM son todos subprocesos de demonio. También existe el grupo de conexiones de la base de datos que se utiliza cuando se realizan aplicaciones de bases de datos. El grupo de conexiones en sí también contiene muchos subprocesos en segundo plano para monitorear el número de conexiones, el período de tiempo de espera, el estado, etc.

De forma predeterminada, el proceso java debe esperar a que finalicen todos los subprocesos antes de que finalice. Hay un subproceso especial llamado subproceso daemon. Cuando todos los subprocesos que no son demonio están terminados, incluso si no está terminado, se verá obligado a finalizar .

2) Métodos que involucran
Llame al método setDaemon (verdadero) del objeto hilo para configurarlo como hilo demonio.

Marque el hilo como un hilo de demonio o un hilo de usuario. Cuando los subprocesos en ejecución son todos subprocesos de demonio, se cierra la máquina virtual Java. Este método debe llamarse antes de iniciar el hilo. Este método primero llama al método checkAccess del hilo sin ningún parámetro. Esto puede generar una SecurityException (en el hilo actual).

public final void setDaemon (boolean on)
Parámetros: on-Si es verdadero, marca el hilo como un hilo demonio.
Lanza:
IllegalThreadStateException-si el hilo está activo.
SecurityException: si el hilo actual no puede modificar el hilo.

3) Propósito del
subproceso del demonio El subproceso del demonio se usa generalmente para realizar algunas tareas en segundo plano, como reproducir música de fondo mientras la aplicación se está ejecutando y realizar una revisión gramatical automática y un guardado automático en un editor de texto.

La recolección de basura de Java también es un hilo de demonio. La ventaja de la línea de guardia es que no necesita preocuparse por su final. Por ejemplo, quieres reproducir música de fondo cuando tu aplicación se está ejecutando. Si configuras el hilo que reproduce música de fondo en un hilo que no sea demonio, cuando el usuario solicite salir, no solo debe salir del hilo principal, sino también notificar la música de fondo para reproducir El hilo sale; si está configurado como hilo demonio, no es necesario.

4.6 Detener el hilo
1) Descripción general
Thread.stop (), Thread.suspend, Thread.resume, Runtime.runFinalizersOnSalir Estos métodos para terminar la ejecución del hilo han sido abandonados y es extremadamente inseguro usarlos.

La forma correcta de detener el hilo:

Primero: el método de ejecución se ejecuta normalmente y luego finaliza.

Segundo: controle la condición de bucle y el identificador de la condición de juicio para finalizar el hilo.

2) 实现 代码 示例
clase MyThread extiende Thread {int i = 0; booleano siguiente = verdadero; @Override public void run () {while (next) {if (i == 10) next = false; i ++; System.out.println (i); }}}

4.7 Interrupción del hilo: interrupción
1) ¿Qué es interrumpir (interrumpir)? La
interrupción es solo un mecanismo cooperativo. Java no agrega ninguna sintaxis para interrumpir. El proceso de interrupción debe ser implementado completamente por los propios programadores;

Cada objeto de hilo tiene una bandera, que se usa para indicar si el hilo está interrumpido, el bit de bandera es verdadero para indicar interrupción y falso para indicar ininterrumpido;

Establezca el indicador del hilo en verdadero llamando al método de interrupción del objeto hilo; se puede llamar en otros hilos o en su propio hilo.

Bandera de interrupción: si el hilo está interrumpido, verdadero significa que está interrumpido, falso significa que no

2) Involucrando el método
isInterrupted () método:

Obtenga la marca de interrupción del hilo (verifique qué objeto de hilo se llama), la marca de interrupción del hilo no se modificará después de la llamada

método interrupt ():

Interrumpe este hilo (qué objeto de hilo se llama para interrumpir a quién). Si el hilo que necesita ser interrumpido está en un estado bloqueado (dormir, esperar, unirse), entonces se borrará su estado interrumpido y se lanzará una excepción (InterruptedException). Esta interrupción no está realmente deteniendo el hilo, pero estableciendo su estado de interrupción en el estado "detenido", el hilo continuará ejecutándose, en cuanto a cómo detener el hilo, todavía tenemos que detenerlo nosotros mismos, este método es solo para detener el subproceso El estado de se establece en el estado "detener", que es verdadero.

Interrumpe un hilo normal, el hilo no se interrumpirá, pero la interrupción del hilo se marca como verdadera.

método interrumpido ():

Compruebe si el hilo actual está interrumpido y utilícelo junto con el método interrupt () anterior. El estado de interrupción del hilo se borrará mediante este método, es decir: si este método se llama con éxito dos veces seguidas, la segunda vez

La llamada devolverá falso (a menos que el hilo actual se interrumpa nuevamente después de la primera llamada y antes de la segunda llamada).

En otras palabras: borre la bandera de interrupción después de la llamada, es decir, si se vuelve verdadera, la bandera de interrupción después de la llamada es falsa (no se usa comúnmente)

4.8. Bloqueo de subprocesos El bloqueo de
subprocesos se puede dividir en muchos tipos. La definición de bloqueo en el nivel del sistema operativo y en el nivel de Java puede ser diferente, pero en un sentido amplio, hay varias formas de bloquear subprocesos:

1) Bloqueo BIO, es decir, se utiliza un flujo io de bloqueo

2) dormir (mucho tiempo) dejar que el hilo duerma en un estado de bloqueo

3) a.join () El hilo que llama a este método entra en bloqueo, esperando que el hilo termine de ejecutarse y continúe ejecutándose

4) sincronizado o ReentrantLock hace que el hilo entre en el estado bloqueado sin adquirir el bloqueo

5) Llamar al método wait () después de adquirir el bloqueo también hará que el hilo entre en el estado de bloqueo

6) LockSupport.park () permite que el hilo entre en estado de bloqueo

V. Resumen de los métodos del núcleo del hilo
5.1. Correspondencia entre los seis estados y métodos del hilo

Inserte la descripción de la imagen aquí

5.2. Resumen de los métodos del núcleo del hilo
1) Métodos del núcleo en la clase de hilo
2) Métodos relacionados con el hilo en Object
Inserte la descripción de la imagen aquí

para resumir
Inserte la descripción de la imagen aquí

Muchas personas se han entrevistado recientemente. He compilado varias copias aquí: materiales de subprocesos múltiples de Java, grupo de la familia Spring (1187 páginas de documentos), materiales sistematizados de Java: (incluidos los últimos puntos de conocimiento básicos de Java en 2021, temas de entrevistas de Java y preguntas reales de Internet , libros electrónicos, etc. resumidos en 21 años), los amigos que lo necesiten pueden unirse al grupo QQ "748945508" para obtenerlos gratis.

Supongo que te gusta

Origin blog.csdn.net/dcj19980805/article/details/114693244
Recomendado
Clasificación