Programación JAVA13-multi-thread


Múltiples hilos pueden ser concurrentes, y cada hilo ejecuta diferentes tareas en paralelo.
Multithreading es una forma especial de multitarea, pero multithreading utiliza menos sobrecarga de recursos.
Aquí se define otro término relacionado con los subprocesos: un proceso incluye espacio de memoria asignado por el sistema operativo y contiene uno o más subprocesos. Un hilo no puede existir independientemente, debe ser parte del proceso. Se ha estado ejecutando un proceso hasta que todos los subprocesos no daemon hayan terminado de ejecutarse antes de que pueda finalizar.
El subprocesamiento múltiple puede satisfacer a los programadores para que escriban programas eficientes para utilizar completamente la CPU.

La relación entre procesos y subprocesos es: un proceso puede contener uno o más subprocesos, pero habrá al menos un subproceso.
Inserte la descripción de la imagen aquí

Crea un nuevo hilo

El lenguaje Java tiene soporte integrado para subprocesos múltiples. Cuando se inicia el programa Java, en realidad inicia un proceso JVM, y luego JVM inicia el hilo principal para ejecutar el método main (). En el método main (), puede iniciar otros hilos.
Java proporciona tres métodos para crear hilos:

  • Al implementar la interfaz Runnable;
  • Al heredar la clase Thread misma;
  • Crea hilos a través de Callable y Future.

Cree un hilo implementando la interfaz Runnable

La forma más fácil de crear un hilo es crear una clase que implemente la interfaz Runnable.
Para implementar Runnable, una clase solo necesita ejecutar un método llamado run (), declarado de la siguiente manera:
public void run ()
Puede anular este método, lo importante es entender que run () puede llamar a otros métodos, usar otras clases y declarar Variables, al igual que el hilo principal.
Después de crear una clase que implemente la interfaz Runnable, puede crear una instancia de un objeto de subproceso en la clase.
Thread define varios métodos de construcción, el siguiente es el que usamos a menudo:
Thread (Runnable threadOb, String threadName);
Aquí, threadOb es una instancia de una clase que implementa la interfaz Runnable, y threadName especifica el nombre del nuevo hilo.
Después de crear el nuevo hilo, se ejecutará solo si llama a su método start ().
void start ();
Aquí hay un ejemplo de cómo crear un hilo y comenzar a ejecutarlo:

class RunnableDemo implements Runnable {
   private Thread t;
   private String threadName;
   
   RunnableDemo( String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      try {
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            // 让线程睡眠一会
            Thread.sleep(50);
         }
      }catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}
 
public class TestThread {
 
   public static void main(String args[]) {
      RunnableDemo R1 = new RunnableDemo( "Thread-1");
      R1.start();
      
      RunnableDemo R2 = new RunnableDemo( "Thread-2");
      R2.start();
   }   
}
编译以上程序运行结果如下:

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

Crear un hilo heredando hilo

La segunda forma de crear un hilo es crear una nueva clase que herede la clase Hilo, y luego crear una instancia de esa clase.
Las clases heredadas deben anular el método run (), que es el punto de entrada para nuevos subprocesos. También debe llamar al método start () para ejecutar.
Aunque este método aparece como una implementación multiproceso, es esencialmente una instancia de la interfaz Runnable.

class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;
   
   ThreadDemo( String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      try {
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            // 让线程睡眠一会
            Thread.sleep(50);
         }
      }catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}
 
public class TestThread {
 
   public static void main(String args[]) {
      ThreadDemo T1 = new ThreadDemo( "Thread-1");
      T1.start();
      
      ThreadDemo T2 = new ThreadDemo( "Thread-2");
      T2.start();
   }   
}

编译以上程序运行结果如下:

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

Método de hilo

La siguiente tabla enumera algunos métodos importantes de la clase Thread:
Inserte la descripción de la imagen aquí
pruebe si el hilo está activo. El método anterior lo llama el objeto Thread. El siguiente método es un método estático de la clase Thread.
Inserte la descripción de la imagen aquí
El siguiente programa ThreadClassDemo muestra algunos métodos de la clase Thread:

DisplayMessage.java 文件代码:
// 文件名 : DisplayMessage.java
// 通过实现 Runnable 接口创建线程
public class DisplayMessage implements Runnable {
   private String message;
   
   public DisplayMessage(String message) {
      this.message = message;
   }
   
   public void run() {
      while(true) {
         System.out.println(message);
      }
   }
}

GuessANumber.java 文件代码:
// 文件名 : GuessANumber.java
// 通过继承 Thread 类创建线程
 
public class GuessANumber extends Thread {
   private int number;
   public GuessANumber(int number) {
      this.number = number;
   }
   
   public void run() {
      int counter = 0;
      int guess = 0;
      do {
         guess = (int) (Math.random() * 100 + 1);
         System.out.println(this.getName() + " guesses " + guess);
         counter++;
      } while(guess != number);
      System.out.println("** Correct!" + this.getName() + "in" + counter + "guesses.**");
   }
}

ThreadClassDemo.java 文件代码:
// 文件名 : ThreadClassDemo.java
public class ThreadClassDemo {
 
   public static void main(String [] args) {
      Runnable hello = new DisplayMessage("Hello");
      Thread thread1 = new Thread(hello);
      thread1.setDaemon(true);
      thread1.setName("hello");
      System.out.println("Starting hello thread...");
      thread1.start();
      
      Runnable bye = new DisplayMessage("Goodbye");
      Thread thread2 = new Thread(bye);
      thread2.setPriority(Thread.MIN_PRIORITY);
      thread2.setDaemon(true);
      System.out.println("Starting goodbye thread...");
      thread2.start();
 
      System.out.println("Starting thread3...");
      Thread thread3 = new GuessANumber(27);
      thread3.start();
      try {
         thread3.join();
      }catch(InterruptedException e) {
         System.out.println("Thread interrupted.");
      }
      System.out.println("Starting thread4...");
      Thread thread4 = new GuessANumber(75);
      
      thread4.start();
      System.out.println("main() is ending...");
   }
}

运行结果如下,每一次运行的结果都不一样。

Starting hello thread...
Starting goodbye thread...
Hello
Hello
Hello
Hello
Hello
Hello
Goodbye
Goodbye
Goodbye
Goodbye
Goodbye
.......

Crea hilos con Callable y Future

  1. Cree una clase de implementación de la interfaz invocable e implemente el método call (). El método call () actuará como el cuerpo de ejecución del subproceso y tendrá un valor de retorno.

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

  3. Use el objeto FutureTask como el objetivo del objeto Thread para crear e iniciar un nuevo hilo.

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

Ejemplos

public class CallableThreadTest implements Callable<Integer> {
    public static void main(String[] args)  
    {  
        CallableThreadTest ctt = new CallableThreadTest();  
        FutureTask<Integer> ft = new FutureTask<>(ctt);  
        for(int i = 0;i < 100;i++)  
        {  
            System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);  
            if(i==20)  
            {  
                new Thread(ft,"有返回值的线程").start();  
            }  
        }  
        try  
        {  
            System.out.println("子线程的返回值:"+ft.get());  
        } catch (InterruptedException e)  
        {  
            e.printStackTrace();  
        } catch (ExecutionException e)  
        {  
            e.printStackTrace();  
        }  
  
    }
    @Override  
    public Integer call() throws Exception  
    {  
        int i = 0;  
        for(;i<100;i++)  
        {  
            System.out.println(Thread.currentThread().getName()+" "+i);  
        }  
        return i;  
    }  
}

Contraste

  1. Cuando se crean varios subprocesos implementando las interfaces ejecutables y invocables, la clase de subprocesos solo implementa la interfaz ejecutable o la interfaz invocable, y también puede heredar otras clases.
  2. Al crear subprocesos múltiples heredando la clase Thread, es fácil de escribir. Si necesita acceder al hilo actual, no necesita usar el método Thread.currentThread (), puede usarlo directamente para obtener el hilo actual.

La clave para el uso efectivo de subprocesos múltiples es comprender que los programas se ejecutan simultáneamente en lugar de en serie. Por ejemplo, hay dos subsistemas en el programa que deben ejecutarse simultáneamente, y luego se requiere una programación multiproceso.

Mediante el uso de subprocesos múltiples, puede escribir programas muy eficientes. Sin embargo, tenga en cuenta que si crea demasiados hilos, la eficiencia de la ejecución del programa se reduce, no mejora.

Recuerde que la sobrecarga de cambio de contexto también es muy importante. ¡Si crea demasiados hilos, la CPU pasará más tiempo cambiando de contexto que ejecutando el programa!

Publicado 23 artículos originales · elogiado 7 · 1002 visitas

Supongo que te gusta

Origin blog.csdn.net/qq_34356768/article/details/105351799
Recomendado
Clasificación