Cuatro métodos para crear subprocesos múltiples en Java, heredar la clase Thread para crear subprocesos múltiples, implementar la interfaz Runnable, crear a través de Callable y Future y usar grupos de subprocesos


Prefacio

¿Por qué utilizar hilos?

Cuando se completa una determinada función en el programa, la describiremos como una tarea, y esta tarea debe completarse en un hilo.


1. Serialización y concurrencia

Si hay varias tareas que deben procesarse en el programa, los métodos de procesamiento en este momento pueden ser en serie o concurrentes:

  • Serial (sincrónico): todas las tareas se ejecutan en un orden determinado. Si la tarea anterior no ha terminado de ejecutarse, la siguiente tarea esperará.
  • Concurrencia (asincrónica): ejecuta múltiples tareas al mismo tiempo y procesa múltiples tareas al mismo tiempo dentro de un período de tiempo.

2. Procesos e hilos

  • Proceso : Es una descripción de los diversos recursos que ocupa un programa durante su operación.
  • Hilo : Es la unidad de ejecución más pequeña del proceso. En el sistema operativo, la unidad de ejecución de tareas más pequeña no es un hilo, sino un identificador. Es solo que el mango es demasiado pequeño y su operación es muy problemática, por lo que el hilo es la unidad de ejecución de tareas más pequeña que podemos controlar.

1. Similitudes y diferencias entre procesos e hilos.

  • Similitud: tanto los procesos como los subprocesos existen para manejar múltiples tareas al mismo tiempo.
  • La diferencia: los recursos no se comparten entre procesos y un proceso no puede acceder a los datos de otro proceso. Los recursos se comparten entre subprocesos y varios subprocesos pueden compartir los mismos datos. Precisamente porque los recursos se comparten entre subprocesos, surgirán problemas críticos de recursos.

2. La relación entre procesos e hilos.

Cuando se crea un proceso, se creará automáticamente un hilo para manejar las tareas del proceso. Este hilo se llama hilo principal. Durante la ejecución del programa, también se pueden abrir otros subprocesos, que son todos subprocesos.
En otras palabras, un proceso puede contener varios subprocesos. Si un subproceso en un proceso falla, siempre que existan otros subprocesos, no afectará la ejecución de todo el proceso. Pero si todos los subprocesos de un proceso terminan de ejecutarse, el proceso también finalizará.

3. Resumen de procesos e hilos.

  • Programa: un archivo ejecutable
  • Proceso: un programa en ejecución, también puede entenderse como abrir un espacio en la memoria.
  • Hilo: Responsable de la ejecución del programa, puede considerarse como un canal de ejecución o unidad de ejecución, por lo que generalmente entendemos el trabajo del proceso como el trabajo del hilo.
  • ¿Puede no haber hilos en un proceso? Debe haber hilos, al menos uno.
  • Cuando hay un subproceso, lo llamamos subproceso único (el único subproceso es el subproceso principal), cuando existe más de un subproceso al mismo tiempo, lo llamamos subproceso múltiple.
  • La función del subproceso múltiple: lograr varias cosas al mismo tiempo (ejecución concurrente).

3. Creación de hilos

1. Cuatro métodos de creación de hilos.

Hay cuatro formas principales de crear hilos:

  • Herede la clase Thread para crear un objeto thread
  • Utilice la interfaz ejecutable
  • Crear hilos a través de Callable y Future
  • Crear subprocesos a través del grupo de subprocesos

2. Herede la clase Thread para crear un objeto thread

Hereda de la clase Thread y crea una subclase de Thread. En la subclase, anule el método de ejecución en la clase principal. En este método anulado, especifique las tareas que este hilo necesita procesar.

Ejemplo de código:

/**
 * @author: Mercury
 * Date: 2022/3/27
 * Time: 13:15
 * Description:通过继承Thread来创建线程
 * Version:1.0
 */
public class Test3 {
    
    
    public static void main(String[] args) {
    
    
        Task2 task2 = new Task2("通过继承Thread创建的线程1");
        task2.start();
    }
}
class Task2 extends Thread{
    
    
    private String threadName;

    public Task2() {
    
    
    }

    public Task2(String threadName) {
    
    
        this.threadName = threadName;
    }
    @Override
    public void run() {
    
    
        for (int i = 0; i < 10; i++) {
    
    
            System.out.println(threadName+": "+i);
        }
    }
}

1) Métodos comunes de la clase Thread

nombre del método describir
hilo actual() Devuelve una referencia al objeto de hilo que se está ejecutando actualmente.
obtenerId() Devuelve el identificador de este hilo.
obtenerNombre() Devuelve el nombre de este hilo.
obtenerPrioridad() Devuelve la prioridad de este hilo.
obtenerEstado() Devuelve el estado de este hilo.
setName(nombre de cadena) Cambie el nombre de este hilo al nombre del parámetro
dormir (milis largos) Hace que el hilo actual se detenga durante el número especificado de milisegundos.
comenzar() Hacer que este hilo comience a ejecutarse.
Encadenar() Devuelve el nombre, la prioridad y el grupo de hilos de este hilo.
producir() Una pista para el programador de que el hilo actual está dispuesto a generar el procesador utilizado actualmente.

3. Utilice la interfaz ejecutable

En el constructor de la clase Thread, hay un constructor sobrecargado cuyo parámetro es la interfaz Runnable. Por lo tanto, se puede crear una instancia del objeto Thread a través del objeto de clase de implementación de la interfaz Runnable.

Ejemplo de código:

/**
 * @author: Mercury
 * Date: 2022/3/27
 * Time: 13:05
 * Description:通过实现Runnable接口来创建线程
 * Version:1.0
 */
public class Test2 {
    
    
    public static void main(String[] args) {
    
    
        Task task = new Task();
        Thread thread = new Thread(task,"线程1");
        thread. start();
    }
}
class Task implements Runnable{
    
    
    @Override
    public void run() {
    
    
        for (int i = 0; i < 10; i++) {
    
    
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

5. Comparación de las ventajas y desventajas de heredar Thread y usar la interfaz Runnable

  • Método de herencia: la ventaja es que es más legible, pero la desventaja es que no es lo suficientemente flexible. Si desea personalizar un hilo, debe heredar de la clase Thread, lo que puede afectar el sistema de herencia original.
  • Método de interfaz: la ventaja es que es flexible y no afecta el sistema de herencia de una clase. La desventaja es la mala legibilidad.

6. Cree hilos a través de Callable y Future.

Cree una clase de implementación de la interfaz Callable e implemente el método call(), que puede usarse como cuerpo de ejecución del subproceso y tiene un valor de retorno. A continuación, cree una instancia de la clase de implementación Callable y use la clase FutureTask 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 de Thread para crear e iniciar un nuevo hilo. Luego llame a get() del objeto FutureTask para obtener el valor de retorno después de que finalice la ejecución del subproceso secundario. Si no necesita aceptar el valor de retorno, no necesita realizar esta parte de la operación.

Ejemplo de código:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @author: Mercury
 * Date: 2022/3/27
 * Time: 13:29
 * Description:通过 Callable 和 Future 创建线程
 * Version:1.0
 */
public class Test4 {
    
    
    public static void main(String[] args) {
    
    
        CallableTest callableTest = new CallableTest();
        //使用FutureTask类包装Callable对象
        FutureTask<Integer> futureTask = new FutureTask<Integer>(callableTest);
        //将FutureTask的对象作为参数传递到Thread类中,创建Thread对象,并调用start()
        new Thread(futureTask).start();
        //如果需要获取返回值的话
        try {
    
    
            Integer i = futureTask.get();
            System.out.println("i="+i);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        } catch (ExecutionException e) {
    
    
            e.printStackTrace();
        }
    }
}
//创建Callable接口的实现类
class CallableTest implements Callable<Integer>{
    
    

    //实现call()方法
    @Override
    public Integer call() throws Exception {
    
    
        int i = 0;
        for (; i < 100; i++) {
    
    
            System.out.println(Thread.currentThread().getName()+": "+i);
        }
        return i;
    }
}

6. Cree subprocesos a través del grupo de subprocesos.

Grupo de subprocesos : en realidad es un contenedor que almacena varios subprocesos.

El objetivo principal del uso de grupos de subprocesos es resolver el problema de la reutilización de subprocesos . Cuando usamos subprocesos antes, cuando necesitábamos usar un subproceso, creamos una instancia de un nuevo subproceso. Cuando se completa el uso de este hilo, este hilo se destruye. No hay ningún problema para el cumplimiento de los requisitos, pero si los subprocesos se abren y destruyen con frecuencia, en realidad es una carga para la CPU, por lo que debemos hacer todo lo posible para optimizar esto.

Este problema se puede resolver mediante un mecanismo de reutilización. Cuando necesitamos usar un subproceso, en lugar de crear una instancia directamente, primero vamos al grupo de subprocesos para encontrar si hay subprocesos inactivos que se puedan usar. Si lo hay, úselo directamente; si no, cree una instancia de un nuevo hilo. Y cuando finaliza el uso de este subproceso, no se destruye inmediatamente, sino que se coloca en el grupo de subprocesos para su uso continuo la próxima vez.

Todos los subprocesos del grupo de subprocesos se pueden dividir en dos partes: subprocesos centrales y subprocesos temporales.

Subprocesos principales : los subprocesos principales residen en el grupo de subprocesos. Estos subprocesos no se destruirán mientras exista el grupo de subprocesos. Se destruirán solo cuando sea necesario destruir el grupo de subprocesos.

Hilo temporal : Es un trabajador temporal. Cuando se encuentran requisitos temporales de subprocesos de alta densidad, algunos subprocesos se abrirán temporalmente para procesar algunas tareas. Una vez que estos subprocesos temporales terminen de procesar las tareas que necesitan procesar, quedarán inactivos si no hay otras tareas que procesar. Cuando el tiempo de inactividad alcance el tiempo especificado, este hilo temporal será destruido.

Ejemplo de código:

package test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author: Mercury
 * Date: 2022/3/27
 * Time: 12:48
 * Description:线程池
 * Version:1.0
 */
public class Test1 {
    
    
    public static void main(String[] args) {
    
    
        //创建线程池对象,参数10 表示线程池中有10个线程
        ExecutorService service = Executors.newFixedThreadPool(10);
        //创建Runnable线程对象
        Task3 task3 = new Task3();
        //从线程池中获取线程对象
        service.submit(task3);
        service.submit(task3);
        //关闭线程池
        service.shutdown();
    }
}
class Task3 implements Runnable{
    
    

    @Override
    public void run() {
    
    
        for (int i = 0; i < 100; i++) {
    
    
            System.out.println(Thread.currentThread().getName()+": "+i);
        }
    }
}

1. Métodos comunes de grupo de subprocesos

método describir
ejecutar (ejecutable ejecutable) Enviar la tarea al grupo de subprocesos, que asigna subprocesos para procesamiento simultáneo
cerrar() Enviar una señal de parada al grupo de subprocesos no detendrá los subprocesos en el grupo de subprocesos, pero finalizará el subproceso y el grupo de subprocesos después de que todas las tareas en el grupo de subprocesos hayan terminado de ejecutarse.
apagar ahora() Detenga inmediatamente todos los subprocesos en el grupo de subprocesos y el grupo de subprocesos

2. Clases de herramientas de grupo de subprocesos

Además de crear una instancia del grupo de subprocesos utilizando el método constructor, el grupo de subprocesos también se puede obtener a través de la clase de herramienta Ejecutores. En las aplicaciones reales, en la mayoría de los escenarios, no puede usar el método de construcción anterior para crear una instancia del grupo de subprocesos, sino usar el método en la clase de herramienta Ejecutores para obtenerlo.

método describir
Ejecutores.newSingleThreadExecutor() Número de subprocesos principales: 1, Número máximo de subprocesos: 1
Ejecutores.newFixedThreadPool (tamaño int) Tamaño de rosca central, tamaño máximo de rosca
entregar() Agregar tareas al grupo de subprocesos
cerrar() Detener grupo de subprocesos

Resumir

Lo anterior es el contenido relacionado con subprocesos múltiples. Presenta brevemente los procesos, subprocesos y los cuatro métodos de creación de subprocesos múltiples. ¡Les deseo a todos un feliz aprendizaje!

Supongo que te gusta

Origin blog.csdn.net/qq_45263520/article/details/123774458
Recomendado
Clasificación