02. El uso de la clase Thread, la API interna de la clase thread se explica en detalle.

1. El método de construcción proporcionado por Thread

La clase Thread nos proporciona un constructor más rico.
Inserte la descripción de la imagen aquí

2. El nombre de los hilos

Varios de los métodos de construcción anteriores no requieren que se pase el nombre del hilo

Inserte la descripción de la imagen aquí

Observe el código fuente para saber
Inserte la descripción de la imagen aquí

Si no se muestra el nombre del hilo, el hilo se combinará con un prefijo de "Thread-" y un número de incremento automático, como: Thread-1, Thread-2 ...

Además del nombre de inicialización del hilo mostrado por el método de construcción, el nombre del hilo también se puede modificar a través de setName (String). Tenga en cuenta que el nombre solo se puede modificar antes de que se inicie el hilo. Una vez que se inicia el hilo, el nombre del hilo no puede ser modificado:
Inserte la descripción de la imagen aquí

3. La relación padre-hijo de los hilos

Mirando de cerca el método de construcción de Thread, puede ver que eventualmente se llamará a un método estático init. En el método, podemos ver que cada hilo recién creado tendrá un hilo padre.

Inserte la descripción de la imagen aquí

currentThread () es un método para obtener el hilo actual, y lo que se obtiene aquí será el hilo antiguo que ejecuta el nuevo método de construcción del hilo. Observando el código en el método, no es difícil encontrar:

1. Un hilo es creado por otro hilo. 2. El hilo principal del hilo creado es el hilo que lo creó.

El hilo principal donde se encuentra la función principal es creado por la JVM. El hilo principal del hilo creado en el método principal es el hilo principal.

La relación ThreadGroup en el hilo padre-hijo:

En el método de construcción de subprocesos, Thread (grupo de ThreadGroup, destino ejecutable) puede especificar explícitamente el ThreadGroup (grupo de subprocesos) del subproceso. ¿Qué pasa si no se especifica? El subproceso se agrega al grupo de subprocesos donde se encuentra el subproceso principal.

La relación de herencia del tutor en subprocesos padre-hijo:

La diferencia entre un hilo de demonio y un hilo de usuario es que el hilo de demonio depende del hilo que lo creó, mientras que el hilo de usuario no. Un ejemplo simple: si se crea un subproceso de demonio en el subproceso principal, el subproceso del demonio morirá después de que finalice el método principal. El hilo del usuario no. El hilo del usuario se ejecutará hasta que termine de ejecutarse. En la JVM, el subproceso del recolector de basura es el subproceso del demonio.

El proceso padre es un subproceso demonio, también lo es el proceso hijo y viceversa. Por supuesto, el hilo hijo puede cambiar la naturaleza de su propio hilo demonio a través de setDaemon (booleano).

4. Resumen de métodos relacionados con los atributos de los hilos

Los siguientes son varios métodos relacionados con los atributos del hilo:

1) getId

Se usa para obtener el ID del hilo

2) getName 和 setName

Se usa para obtener o establecer el nombre del hilo.

3) getPriority 和 setPriority

Se usa para obtener y establecer la prioridad de los subprocesos.

4) setDaemon e isDaemon

Se utiliza para establecer si el subproceso es un subproceso demonio y para determinar si el subproceso es un subproceso demonio.

5) hilo actual

La clase Thread tiene un método estático de uso más común currentThread () para obtener el hilo actual.

4. Introducción detallada de la API de subprocesos

1) método de inicio

Start () se utiliza para iniciar un hilo. Cuando se llama al método de inicio, el sistema iniciará un nuevo hilo para realizar las subtareas definidas por el usuario. En este proceso, al hilo correspondiente se le asignarán los recursos necesarios. Una instancia de subproceso no se puede contar como un subproceso antes de que se llame al método de inicio, es solo una instancia de clase de subproceso normal.

2) método de ejecución

El usuario no necesita llamar al método run (). Cuando un hilo se inicia a través del método de inicio, cuando el hilo obtiene el tiempo de ejecución de la CPU, ingresa al cuerpo del método de ejecución para realizar tareas específicas. Tenga en cuenta que heredar la clase Thread debe anular el método de ejecución y definir las tareas específicas que se realizarán en el método de ejecución.

3) método de sueño

dormir es un método estático, hay 2 métodos sobrecargados

  1.public static native void sleep(long millis) throws InterruptedException; //参数为毫秒
  
  2.public static void sleep(long millis, int nanos) throws InterruptedException   //第一参数为毫秒,第二个参数为纳秒`

La suspensión hará que el hilo actual se suspenda durante la cantidad especificada de milisegundos, entregue la CPU y deje que la CPU realice otras tareas.

Una característica muy importante de dormir al entrar en suspensión es que no renunciará a la propiedad del bloqueo del monitor, lo que significa que si el hilo actual mantiene un bloqueo en un objeto, incluso si se llama al método de suspensión, otros hilos no pueden acceder a este objeto. .

Utilice TimeUnit en lugar de Thread.sleep:

Después de JDK1.5, JDK introdujo una enumeración TimeUnit, que encapsuló el método de suspensión una vez, lo que puede hacer que el tiempo de suspensión limitado por el sueño se vuelva muy intuitivo.

//让线程睡眠1小时18分26秒又7毫秒
TimeUnit.HOURS.sleep(1);
TimeUnit.MINUTES.sleep(18);
TimeUnit.SECONDS.sleep(26);
TimeUnit.MILLISECONDS.sleep(7);

4) Método de rendimiento

Llamar al método de rendimiento hará que el subproceso actual ceda los permisos de la CPU y permita que la CPU ejecute otros subprocesos. Es similar al método de suspensión y el bloqueo tampoco se libera. El método de rendimiento es un método heurístico que le recuerda al programador que estoy dispuesto a ceder los recursos de la CPU actual, pero que la CPU no se ejecuta necesariamente. Cuando los recursos de la CPU no son limitados, este recordatorio se ignorará. Por lo tanto, yield no puede controlar el tiempo específico para entregar la CPU, sino que solo permite que los subprocesos con la misma prioridad tengan la oportunidad de obtener el tiempo de ejecución de la CPU.

Tenga en cuenta que llamar al método yield no hace que el subproceso entre en el estado bloqueado, pero hace que el subproceso vuelva al estado listo. Solo necesita esperar para recuperar el tiempo de ejecución de la CPU, que es diferente del método de suspensión.

La diferencia entre los métodos de sueño y rendimiento:

1. La suspensión hará que el subproceso actual se suspenda durante un tiempo específico, sin el consumo de los intervalos de tiempo de la CPU.

2. El conocimiento de rendimiento es una sugerencia para la programación de la CPU. Si la CPU no ignora la sugerencia, hará que el contexto del hilo cambie

3. La suspensión bloqueará el hilo durante un breve período de tiempo y liberará los recursos de la CPU en un tiempo determinado.

4.El rendimiento hará que el hilo en el estado RUNNINGz entre en el estado RUNNABLE

5.Dormir definitivamente puede completar el sueño durante el tiempo especificado, y el aviso de rendimiento no necesariamente garantiza

6. Un hilo en reposo, otra interrupción de llamadas de hilo capturará la señal de interrupción, pero el rendimiento no lo hará.

5) Método de interrupción

interrumpir, como su nombre lo indica, significa interrupción. Los métodos que usamos a menudo relacionados con la interrupción del hilo son los siguientes 3

1.public void interrupt() {}

2.public static boolean interrupted() 

3.public boolean isInterrupted() 

1.interrumpir ():

La llamada del siguiente método hará que el hilo actual entre en el estado de bloqueo y llame al método de interrupción del hilo actual. El bloqueo se puede interrumpir.

Inserte la descripción de la imagen aquí

El método anterior hará que el subproceso actual entre en estado de bloqueo. Si otro subproceso llama al método de interrupción del subproceso bloqueado, el bloqueo se interrumpirá. Por lo tanto, este método a veces se denomina método interrumpible. Tenga en cuenta que interrumpir un subproceso no implica Es igual al final del ciclo de vida del subproceso, que simplemente interrumpe el estado de bloqueo actual del subproceso.

Una vez que un hilo se interrumpe en un estado bloqueado, se lanzará una excepción llamada InterruptedException. Esta excepción es como una señal para notificar que el hilo actual está interrumpido.

Thread t = new Thread(()->{
    
    
    try{
    
    
        System.out.println("我开始睡了");
        TimeUnit.MINUTES.sleep(1);
        System.out.println("我睡了一分钟");
    }catch (InterruptedException e){
    
    
        System.out.println("我被打断了:"+e.getMessage());
    }
});
t.start();
TimeUnit.SECONDS.sleep(2);
t.interrupt();

//运行结果
我开始睡了
我被打断了:sleep interrupted

El código anterior crea un hilo y se prepara para dormir durante 1 minuto, sin embargo, el hilo principal llama al método de interrupción del hilo después de dos segundos y luego se interrumpe el sueño.

¿Qué hace exactamente el método de interrupción? Hay un indicador llamado indicador de interrupción en el hilo. Si se interrumpe un hilo, este indicador se establecerá, pero si el hilo actual está ejecutando un método interrumpible está bloqueado, llamar al método de interrupción para interrumpir hará que el indicador se elimine. . Tenga en cuenta que si un hilo ha muerto, el intento de interrumpirlo se ignorará directamente.

2.está interrumpido

isInterrupted es un método miembro de Thread. Determina principalmente si se interrumpe el hilo actual. El método es solo un juicio sobre la bandera de interrupción y no afecta el cambio de la bandera.

3.interrumpido

Interrumpido es un método estático. Aunque también se utiliza para determinar si el hilo actual está interrumpido, sigue siendo muy diferente del método miembro isInterrupted. El método de llamada borrará directamente el indicador de interrupción del hilo. Tenga en cuenta que si el hilo actual is Si se interrumpe el hilo, la primera llamada al método interrumpido devolverá falso, y la bandera de interrupción se borrará inmediatamente, y la segunda vez, incluidas las llamadas posteriores, devolverá falso, a menos que el hilo se interrumpa de nuevo.

public static void main(String args[]) throws Exception{
    
    
    Thread t = new Thread(()->{
    
    
        System.out.println(Thread.interrupted());
        //中断
        Thread.currentThread().interrupt();
        System.out.println(Thread.interrupted());
        System.out.println(Thread.interrupted());
    });
    t.start();
}

//运行结果
false
true
false

6) método de unión

Hay tres versiones sobrecargadas del método de unión:

1.public final void join() throws InterruptedException

2.public final synchronized void join(long millis)throws InterruptedException //参数为毫秒 

3.public final synchronized void join(long millis, int nanos)throws InterruptedException  //第一参数为毫秒,第二个参数为纳秒 

Unirse a un hilo A hará que el hilo B actual entre y así sucesivamente, hasta que el hilo A finalice su ciclo de vida, o llegue a un tiempo determinado, durante el cual el hilo B está BLOQUEADO en lugar del hilo A.

public class Try {
    
    
    public static void main(String args[]) throws Exception{
    
    
        //1.定义两个线程并启动
        List<Thread> threadList = IntStream.range(1,3).mapToObj(Try::create).collect(Collectors.toList());
        threadList.forEach(Thread::start);
        //2.在main线程中调用这两线程的join方法
        for (Thread t: threadList) {
    
    
            t.join();
        }
        //3.main线程循环输出
        for (int i = 0; i < 3; i++) {
    
    
            System.out.println(Thread.currentThread().getName()+">>>"+i);
            try{
    
    
                TimeUnit.SECONDS.sleep(1);
            }catch (InterruptedException e){
    
    
            }
        }
    }
}

En el código anterior, después de que se crean dos subprocesos, el método de unión se llama cíclicamente en el subproceso principal, por lo que el subproceso principal se bloqueará hasta el final de los dos subprocesos. La salida será la siguiente, el subproceso principal comenzará a emitirse solo después de que finalice la salida alternativa de los dos subprocesos:

Inserte la descripción de la imagen aquí

Si el subproceso principal necesita esperar hasta el final del subproceso secundario para realizar algunas operaciones, puede usar join para lograr este escenario.

7) Métodos relacionados con el cargador de clases de contexto de subprocesos

1.public ClassLoader getContextClassLoader ()

getContextClassLoader () Obtiene el cargador de clases del contexto del hilo. En resumen, a través de este método, puede saber qué cargador de clases está cargado por el hilo. Si el cargador de clases del contexto del hilo no se modifica, mantenga el hilo padre en el mismo cargador de clases.

2.public void setContextClassLoader (ClassLoader cl)

Establezca el cargador de clases del hilo. Este método puede romper el mecanismo de delegación padre del cargador de clases JAVA. A veces, este método también se denomina puerta trasera del cargador de clases JAVA.

8) método de detención (obsoleto) y método de destrucción (obsoleto)

El método de detención ya es un método obsoleto, es un método inseguro. Debido a que llamar al método de detención terminará directamente la llamada del método de ejecución y arrojará un error de ThreadDeath, si el hilo mantiene un bloqueo de objeto, lo liberará por completo, lo que dará como resultado un estado de objeto inconsistente. Por lo tanto, básicamente no se utiliza el método de parada.

Supongo que te gusta

Origin blog.csdn.net/weixin_43828467/article/details/110482618
Recomendado
Clasificación