Entrevista sobre Java 2024: subprocesos múltiples (1)

Índice de contenidos de los artículos de la serie.

  1. Entrevista sobre Java 2024 (1) - Capítulo de primavera
  2. Entrevista sobre Java 2024 (2) - Capítulo de primavera
  3. Entrevista sobre Java 2024 (3) - Capítulo de primavera
  4. Entrevista sobre Java 2024 (4) - Capítulo de primavera


Programación de hilos

Cinco estados de hilos

Estado del hilo: creado, listo, en ejecución, bloqueado, muerto

1. Nuevo estado (Nuevo): después de crear el objeto de hilo, ingresa al nuevo estado. Por ejemplo, Hilo hilo = nuevo Hilo().

2. Estado listo (ejecutable): también conocido como "estado ejecutable". Una vez creado el objeto de subproceso, otros subprocesos llaman al método start () del objeto para iniciar el subproceso. Por ejemplo, hilo.start(). La CPU puede programar la ejecución de subprocesos en estado listo en cualquier momento.

3. Estado de ejecución (en ejecución): el subproceso obtiene permisos de CPU para su ejecución. Cabe señalar que un hilo solo puede ingresar al estado de ejecución desde el estado listo.

4. Bloqueado: el estado bloqueado significa que el hilo renuncia al derecho de usar la CPU por algún motivo y deja de ejecutarse temporalmente. Hasta que el hilo entre en el estado listo, tiene la posibilidad de pasar al estado en ejecución. Hay tres tipos de situaciones de bloqueo:
(1) Espera de bloqueo: el subproceso en ejecución ejecuta el método de espera, el subproceso liberará todos los recursos ocupados y la JVM colocará el subproceso en el "grupo de espera". Después de entrar en este estado, no se puede despertar automáticamente. Debe depender de otros subprocesos para llamar al método notify o notifyAll para ser despertado. wait es un método de la clase de objeto (2). Bloqueo sincrónico: cuando el subproceso en ejecución adquiere la
sincronización bloqueo del objeto, si el bloqueo de sincronización está ocupado por otro subproceso, la VM colocará el subproceso en el "grupo de bloqueo".
(3) Otros bloqueos: cuando un subproceso en ejecución ejecuta el método de suspensión o unión, o emite una solicitud de E/S, la JVM pondrá el subproceso en un estado bloqueado. Cuando el estado de suspensión se agota, el subproceso en espera de unión finaliza o se agota el tiempo de espera, o se completa el procesamiento de E/S, el subproceso vuelve al estado listo. dormir es un método de la clase Thread

5. Estado de muerte (muerto): el hilo terminó de ejecutarse o salió del método run () debido a una excepción y el hilo finaliza su ciclo de vida.

Insertar descripción de la imagen aquí

Cambio de estado del hilo

método efecto la diferencia
comenzar Inicie el hilo y la máquina virtual programará y ejecutará automáticamente el método run() El hilo está en estado listo.
correr Procesamiento de bloques de código lógico de subprocesos, ejecución de programación JVM El hilo esta corriendo
dormir Dejar que el hilo que se está ejecutando actualmente duerma (pausar la ejecución) No soltar el bloqueo
esperar Hacer esperar el hilo actual Liberar bloqueo de sincronización
notificar Despierta un único hilo esperando en este monitor de objetos Despierta un solo hilo
notificar a todos Despierte todos los hilos que esperan en este monitor de objetos Despierta múltiples hilos
yilado Detener el hilo actual y dejar que se ejecuten hilos de igual prioridad Llamado usando la clase Thread
unirse Haga que el hilo actual se detenga y espere hasta que termine otro hilo que llama al método de unión Llamar con objeto de hilo

Después de la ejecución de rendimiento () , el subproceso ingresa directamente al estado listo, liberando inmediatamente el derecho de ejecución de la CPU, pero aún conserva la calificación de ejecución de la CPU, por lo que es posible que la próxima vez que la CPU realice la programación de subprocesos, el El hilo obtendrá el derecho de ejecución y continuará la ejecución.

Después de ejecutar join (), el subproceso ingresa al estado de bloqueo. Por ejemplo, si se llama a join () del subproceso A en el subproceso B, el subproceso B ingresará a la cola de bloqueo hasta que el subproceso A finalice o el subproceso se interrumpa .

La diferencia entre esperar y dormir

  • El método de espera debe usarse en código protegido sincronizado, pero el método de suspensión no tiene este requisito.
  • El método de espera liberará activamente el bloqueo. Cuando se ejecuta el método de suspensión en el código de sincronización, el bloqueo no se liberará.
  • El método de espera significa esperar eternamente hasta que se interrumpa o despierte antes de poder reanudarse. No se reanudará activamente. Se definirá un tiempo en el método de suspensión y se reanudará automáticamente una vez que expire el tiempo.
  • esperar/notificar es un método de la clase Object y dormir es un método de la clase Thread.

La diferencia entre proceso e hilo.

1. Diferencia fundamental: un proceso es la unidad más pequeña para la asignación de recursos por parte del sistema operativo y un subproceso es la unidad más pequeña para la programación de operaciones por parte del sistema operativo.

2. La relación de afiliación es diferente: el proceso contiene subprocesos y los subprocesos pertenecen al proceso.

3. El costo es diferente: el costo de crear, destruir y cambiar procesos es mucho mayor que el de los subprocesos.

4. Poseer diferentes recursos: cada proceso tiene su propia memoria y recursos, y los subprocesos de un proceso comparten estos recuerdos y recursos.

5. Diferentes capacidades de control e influencia: después de que un proceso falla, no afectará a otros procesos en modo protegido, pero si un subproceso falla, todo el proceso morirá. Por tanto, el multiproceso es más robusto que el multiproceso.

6. Utilización diferente de la CPU: la utilización de la CPU del proceso es baja porque la sobrecarga del cambio de contexto es grande, mientras que la utilización de la CPU del subproceso es alta y el cambio de contexto es rápido.

7. Diferentes operadores: el operador de un proceso suele ser el sistema operativo y el operador de un hilo suele ser un programador.


Cuatro formas de implementar subprocesos múltiples

Heredar la clase Thread para implementar subprocesos múltiples

La clase heredada Thread es una clase funcional que admite subprocesos múltiples y se puede lograr mediante la creación de una subclase.

El punto de partida de todos los programas Java es el método principal, por lo que el hilo debe tener su propio punto de partida, y este punto de partida es el método de ejecución, porque el método de ejecución de Thread debe reescribirse en cada clase principal de subprocesos múltiples.

Este método de ejecución no tiene valor de retorno, lo que significa que una vez que se inicia el hilo, continuará ejecutándose y no podrá devolver contenido.

La única forma de iniciar subprocesos múltiples es llamar al método de inicio de Thread. Si se llama al método de ejecución, es una llamada al método de ejecución ordinario (llamar a este método ejecuta el cuerpo del método de ejecución).

Resumen: el uso del método de inicio de la clase Thread no solo inicia el código de ejecución de subprocesos múltiples, sino que también asigna recursos de diferentes sistemas operativos.

paso:

1. Cree una subclase que herede de la clase Thread.

2. Reescribir run() de la clase Thread --> declarar las operaciones realizadas por este hilo en run()

3. Crea un objeto de una subclase de la clase Thread.

4. Llame a start() a través de este objeto: funciones start() para ① iniciar el hilo actual ② llamar a run() del hilo actual

Heredar la clase Thread (Java no admite herencia múltiple)

public class ExtendsThread extends Thread {
    
    
    @Override
    public void run() {
    
    System.out.println('用Thread类实现线程');}
}

Implementar ejecutable (preferido)

Java tiene la limitación de la herencia única. Todos los programas Java deben evitar la herencia de clases, y lo mismo ocurre con los subprocesos. Para resolver las limitaciones de la herencia única, se crea la interfaz Runnable.

Uso: simplemente deje que una clase implemente la interfaz Runnable y también debe anular el método run().

Pregunta: Pero esta interfaz solo tiene un método de ejecución y ningún método de inicio ¿Cómo iniciar subprocesos múltiples?

En cualquier caso, si desea iniciar subprocesos múltiples, debe confiar en la clase Thread. Los parámetros de la clase Thread son los métodos constructores de los parámetros ejecutables:

Thread (destino ejecutable) recibe la interfaz Runnable

Puede crear una clase Thread cuyo parámetro sea la clase de implementación Runnable y llamar al método de inicio para iniciarla.

Resumen: implemente la interfaz Runnable para escribir clases comerciales de subprocesos múltiples y use Thread para iniciar subprocesos múltiples.

Implementar la interfaz Runnable (preferida)

public class RunnableThread implements Runnable {
    
    
    @Override
    public void run() {
    
    System.out.println('用实现Runnable接口实现线程');}
}

Implementar la interfaz invocable

Implementar la interfaz invocable (con un valor de retorno que puede generar una excepción)

paso:

1. Implementar la interfaz invocable

2. Vuelva a escribir el método Call en el interior (tenga en cuenta que es Call, no Run)

3. Cree un objeto de la clase de implementación invocable.

4. Pase el objeto de clase de implementación como parámetro al constructor FutureTask

5. Pase el objeto FutureTask como parámetro al constructor Thread (debido a que FutureTask implementa la interfaz Runnable, se puede pasar así)

6. Llame al método de inicio de la clase Thread.

//class CallableTask implements Callable<Integer> {
    
    
    //@Override
    //public Integer call() throws Exception { return new Random().nextInt();}
//}
@Override
    public Object call() throws Exception {
    
    
        System.out.println("CallableImpl");
        return "我是Call方法的返回值";
    }public static void main(String[] args) {
    
    
        CallableImpl callable=new CallableImpl();
        FutureTask<Object> futureTask=new FutureTask<>(callable);
        Thread thread=new Thread(futureTask);
       
        需要注意一件事:
        FutureTask类中的get方法获取返回值只能执行一次
        而且,如果使用了这个方法但是线程还没有运行到可以返回的那行代码,那么就会一直阻塞
        比如如果我在这里执行了如下代码:
        Object result=futureTask.get();
        那么就永远阻塞了
        当然,我更想说的是,如果你使用的是这种方法创建线程并且需要返回值的话,里面就别写死循环
        否则就是死锁在召唤
            
        thread.start();
        try {
    
    
            Object result=futureTask.get();
            System.out.println(result);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        } catch (ExecutionException e) {
    
    
            e.printStackTrace();
        }
    }

¿Cómo entender que crear subprocesos múltiples implementando la interfaz Callable es más poderoso que crear subprocesos múltiples implementando la interfaz Runnable?

1.call() puede devolver un valor.

2.call () puede generar una excepción y ser capturada por operaciones externas para obtener información de excepción.

3.Callable admite genéricos

Supongo que te gusta

Origin blog.csdn.net/weixin_43228814/article/details/132598700
Recomendado
Clasificación