Maison > Java > javaDidacticiel > Explication détaillée de l'utilisation du multi-threading en Java

Explication détaillée de l'utilisation du multi-threading en Java

黄舟
Libérer: 2017-09-08 11:15:15
original
1235 Les gens l'ont consulté

Cet article présente principalement des informations pertinentes sur l'utilisation détaillée du multi-threading Java. J'espère que cet article pourra aider tout le monde. Les amis dans le besoin peuvent se référer à

Introduction détaillée à l'utilisation du multi-thread Java. -threading.

L'analyse la plus complète de l'utilisation du multi-threading Java. Si vous n'avez pas effectué de recherches approfondies sur le mécanisme multi-threading de Java, cet article peut vous aider à mieux comprendre les principes et les principes. utilisation du multi-threading Java.

1. Créer un fil de discussion

Il existe deux façons de créer un fil de discussion en Java : en utilisant la classe Thread et en utilisant l'interface Runnable. Lorsque vous utilisez l'interface Runnable, vous devez créer une instance de Thread. Par conséquent, que vous créiez un thread via la classe Thread ou l'interface Runnable, vous devez créer une instance de la classe Thread ou de sa sous-classe. Constructeur de thread :


public Thread( );
public Thread(Runnable target);
public Thread(String name);
public Thread(Runnable target, String name);
public Thread(ThreadGroup group, Runnable target);
public Thread(ThreadGroup group, String name);
public Thread(ThreadGroup group, Runnable target, String name);
public Thread(ThreadGroup group, Runnable target, String name, long stackSize);
Copier après la connexion

Méthode 1 : hériter de la classe Thread et remplacer la méthode run


public class ThreadDemo1 {
   public static void main(String[] args){
     Demo d = new Demo();
     d.start();
     for(int i=0;i<60;i++){
       System.out.println(Thread.currentThread().getName()+i);
     }

   }
 }
 class Demo extends Thread{
   public void run(){
     for(int i=0;i<60;i++){
       System.out.println(Thread.currentThread().getName()+i);
     }
   }
 }
Copier après la connexion

méthode 2 :


public class ThreadDemo2 {
  public static void main(String[] args){
    Demo2 d =new Demo2();
    Thread t = new Thread(d);
    t.start();
    for(int x=0;x<60;x++){
      System.out.println(Thread.currentThread().getName()+x);
    }
  }
}
class Demo2 implements Runnable{
  public void run(){
    for(int x=0;x<60;x++){
      System.out.println(Thread.currentThread().getName()+x);
    }
  }
}
Copier après la connexion

2. Le cycle de vie des fils

Tout comme les gens vivent la naissance, la vieillesse, maladie et mort, les fils doivent aussi passer par le début. Il y a quatre états différents : (attendre), courir, suspendre et s'arrêter. Ces quatre états peuvent être contrôlés via des méthodes de la classe Thread. Les méthodes liées à ces quatre états dans la classe Thread sont indiquées ci-dessous.


// 开始线程
publicvoid start( );
publicvoid run( );
// 挂起和唤醒线程
publicvoid resume( );   // 不建议使用
publicvoid suspend( );  // 不建议使用
publicstaticvoid sleep(long millis);
publicstaticvoid sleep(long millis, int nanos);
// 终止线程
publicvoid stop( );    // 不建议使用
publicvoid interrupt( );
// 得到线程状态
publicboolean isAlive( );
publicboolean isInterrupted( );
publicstaticboolean interrupted( );
// join方法
publicvoid join( ) throws InterruptedException;
Copier après la connexion

Le thread n'exécute pas le code dans la méthode run immédiatement après son établissement, mais est dans un état d'attente. Lorsque le thread est en attente, vous pouvez définir divers attributs du thread via les méthodes de la classe Thread, tels que la priorité du thread (setPriority), le nom du thread (setName) et le type de thread (setDaemon).

Lorsque la méthode start est appelée, le thread commence à exécuter le code dans la méthode run. Le thread entre dans l'état d'exécution. Vous pouvez utiliser la méthode isAlive de la classe Thread pour déterminer si le thread est en cours d'exécution. Lorsque le thread est à l'état d'exécution, isAlive renvoie true. Lorsque isAlive renvoie false, le thread peut être à l'état d'attente ou à l'état arrêté. Le code suivant illustre la commutation entre les trois états de création de thread, d'exécution et d'arrêt, et génère la valeur de retour isAlive correspondante.

Une fois qu'un thread commence à exécuter la méthode run, il ne se terminera pas tant que la méthode run n'est pas terminée. Cependant, pendant l'exécution du thread, vous pouvez arrêter temporairement l'exécution du thread via deux méthodes. Ces deux méthodes sont la suspension et la mise en veille. Après avoir utilisé suspend pour suspendre un thread, vous pouvez le réactiver via la méthode de reprise. Après avoir utilisé sleep pour mettre le thread en veille, le thread ne peut être dans l'état prêt qu'après le temps défini (une fois la veille du thread terminée, le thread peut ne pas s'exécuter immédiatement, mais entre uniquement dans l'état prêt, en attendant que le système planifie) .

Il y a deux points à noter lors de l'utilisation de la méthode sleep :

1. La méthode sleep a deux formes surchargées. L'une des formes surchargées peut non seulement définir des millisecondes, mais également des nanosecondes. 1 000 000 de nanosecondes équivaut à 1 milliseconde). Cependant, la machine virtuelle Java sur la plupart des plates-formes de système d'exploitation n'est pas précise en nanosecondes. Par conséquent, si les nanosecondes sont définies pour la veille, la machine virtuelle Java prendra la milliseconde la plus proche de cette valeur.

2. Les lancers ou try{…}catch{…} doivent être utilisés lors de l'utilisation de la méthode du sommeil. Étant donné que la méthode run ne peut pas utiliser de lancers, vous ne pouvez utiliser que try{…}catch{…}. Lorsque le thread est en veille et que la méthode d'interruption est utilisée pour interrompre le thread, sleep lèvera une InterruptedException. La méthode sleep est définie comme suit :


publicstaticvoid sleep(long millis) throws InterruptedException
publicstaticvoid sleep(long millis, int nanos) throws InterruptedException
Copier après la connexion

Il existe trois façons de terminer un thread.

1. Utilisez l'indicateur de sortie pour que le thread se termine normalement, c'est-à-dire que le thread se termine lorsque la méthode d'exécution est terminée.

2. Utilisez la méthode stop pour terminer de force le thread (cette méthode n'est pas recommandée car l'arrêt, comme la suspension et la reprise, peut également produire des résultats imprévisibles).

3. Utilisez la méthode d'interruption pour interrompre le fil.

1. Utilisez l'indicateur de sortie pour terminer le thread

Lorsque la méthode run est exécutée, le thread se fermera. Mais parfois, la méthode run ne se termine jamais. Par exemple, les threads sont utilisés dans les programmes serveur pour surveiller les demandes des clients ou d'autres tâches nécessitant un traitement cyclique. Dans ce cas, ces tâches sont généralement placées dans une boucle, comme une boucle while. Si vous souhaitez que la boucle s'exécute indéfiniment, vous pouvez utiliser while(true){…} pour la gérer. Mais si vous souhaitez que la boucle while se termine dans certaines conditions, le moyen le plus direct consiste à définir un indicateur de type booléen et à définir cet indicateur sur true ou false pour contrôler si la boucle while se termine. Un exemple de terminaison d’un thread à l’aide de l’indicateur de sortie est donné ci-dessous.

La fonction de la méthode join est de transformer les threads d'exécution asynchrones en exécution synchrone. C'est-à-dire que lorsque la méthode start de l'instance de thread est appelée, cette méthode sera immédiatement renvoyée. Si vous devez utiliser une valeur calculée par ce thread après avoir appelé la méthode start, vous devez utiliser la méthode join. Si vous n'utilisez pas la méthode join, rien ne garantit que lorsqu'une instruction suivant la méthode start est exécutée, le thread sera exécuté. Après avoir utilisé la méthode join, le programme ne poursuivra pas son exécution tant que ce thread ne se terminera pas. Le code suivant montre l'utilisation de join.

3. Problèmes de sécurité multithread

问题原因:当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没执行完,另一个线程参与进来执行,导致共享数据的错误。

解决办法:对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不执行。

同步代码块:


public class ThreadDemo3 {
  public static void main(String[] args){
    Ticket t =new Ticket();
    Thread t1 = new Thread(t,"窗口一");
    Thread t2 = new Thread(t,"窗口二");
    Thread t3 = new Thread(t,"窗口三");
    Thread t4 = new Thread(t,"窗口四");
    t1.start();
    t2.start();
    t3.start();
    t4.start();
  }
}
class Ticket implements Runnable{
  private int ticket =400;
  public void run(){
    while(true){
      synchronized (new Object()) {
        try {
          Thread.sleep(1);
        } catch (InterruptedException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
        if(ticket<=0)
          break;
        System.out.println(Thread.currentThread().getName()+"---卖出"+ticket--);
      }
    }
  }
}
Copier après la connexion

同步函数


public class ThreadDemo3 {
  public static void main(String[] args){
    Ticket t =new Ticket();
    Thread t1 = new Thread(t,"窗口一");
    Thread t2 = new Thread(t,"窗口二");
    Thread t3 = new Thread(t,"窗口三");
    Thread t4 = new Thread(t,"窗口四");
    t1.start();
    t2.start();
    t3.start();
    t4.start();
  }
}
class Ticket implements Runnable{
  private int ticket = 4000;
  public synchronized void saleTicket(){
    if(ticket>0)
      System.out.println(Thread.currentThread().getName()+"卖出了"+ticket--);

  }
  public void run(){
    while(true){
      saleTicket();
    }
  }
}
Copier après la connexion

同步函数锁是this 静态同步函数锁是class

线程间的通信


public class ThreadDemo3 {
  public static void main(String[] args){
    class Person{
      public String name;
      private String gender;
      public void set(String name,String gender){
        this.name =name;
        this.gender =gender;
      }
      public void get(){
        System.out.println(this.name+"...."+this.gender);
      }
    }
    final Person p =new Person();
    new Thread(new Runnable(){
      public void run(){
        int x=0;
        while(true){
          if(x==0){
            p.set("张三", "男");
          }else{
            p.set("lili", "nv");
          }
          x=(x+1)%2;
        }
      }
    }).start();
    new Thread(new Runnable(){
      public void run(){
        while(true){
          p.get();
        }
      }
    }).start();
  }
}
/*
张三....男
张三....男
lili....nv
lili....男
张三....nv
lili....男
*/
Copier après la connexion

修改上面代码


public class ThreadDemo3 {
   public static void main(String[] args){
     class Person{
       public String name;
       private String gender;
       public void set(String name,String gender){
         this.name =name;
         this.gender =gender;
       }
       public void get(){
         System.out.println(this.name+"...."+this.gender);
       }
     }
     final Person p =new Person();
     new Thread(new Runnable(){
       public void run(){
         int x=0;
         while(true){
           synchronized (p) {
             if(x==0){
               p.set("张三", "男");
             }else{
               p.set("lili", "nv");
             }
             x=(x+1)%2;  
           }

         }
       }
     }).start();
     new Thread(new Runnable(){
       public void run(){
         while(true){
           synchronized (p) {
             p.get();
           }
         }
       }
     }).start();
   }

 }
 /*
 lili....nv
 lili....nv
 lili....nv
 lili....nv
 lili....nv
 lili....nv
 张三....男
 张三....男
 张三....男
 张三....男
 */
Copier après la connexion

等待唤醒机制


/*
 *线程等待唤醒机制
 *等待和唤醒必须是同一把锁 
 */
public class ThreadDemo3 {
  private static boolean flags =false;
  public static void main(String[] args){
    class Person{
      public String name;
      private String gender;
      public void set(String name,String gender){
        this.name =name;
        this.gender =gender;
      }
      public void get(){
        System.out.println(this.name+"...."+this.gender);
      }
    }
    final Person p =new Person();
    new Thread(new Runnable(){
      public void run(){
        int x=0;
        while(true){
          synchronized (p) {
            if(flags)
              try {
                p.wait();
              } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
              };
            if(x==0){
              p.set("张三", "男");
            }else{
              p.set("lili", "nv");
            }
            x=(x+1)%2;
            flags =true;
            p.notifyAll();
          }
        }
      }
    }).start();
    new Thread(new Runnable(){
      public void run(){
        while(true){
          synchronized (p) {
            if(!flags)
              try {
                p.wait();
              } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
              };
            p.get();
            flags =false;
            p.notifyAll();
            }
        }
      }
    }).start();
  }
}
Copier après la connexion

生产消费机制一


public class ThreadDemo4 {
  private static boolean flags =false;
  public static void main(String[] args){
    class Goods{
      private String name;
      private int num;
      public synchronized void produce(String name){
        if(flags)
          try {
            wait();
          } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
        this.name =name+"编号:"+num++;
        System.out.println("生产了...."+this.name);
        flags =true;
        notifyAll();
      }
      public synchronized void consume(){
        if(!flags)
          try {
            wait();
          } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
        System.out.println("消费了******"+name);
        flags =false;
        notifyAll();
      }

    }
    final Goods g =new Goods();
    new Thread(new Runnable(){
      public void run(){
        while(true){
          g.produce("商品");
        }
      }
    }).start();
    new Thread(new Runnable(){
      public void run(){
        while(true){
          g.consume();
        }
      }
    }).start();
  }
}
Copier après la connexion

生产消费机制2


public class ThreadDemo4 {
  private static boolean flags =false;
  public static void main(String[] args){
    class Goods{
      private String name;
      private int num;
      public synchronized void produce(String name){
        while(flags)
          try {
            wait();
          } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
        this.name =name+"编号:"+num++;
        System.out.println(Thread.currentThread().getName()+"生产了...."+this.name);
        flags =true;
        notifyAll();
      }
      public synchronized void consume(){
        while(!flags)
          try {
            wait();
          } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
        System.out.println(Thread.currentThread().getName()+"消费了******"+name);
        flags =false;
        notifyAll();
      }

    }
    final Goods g =new Goods();
    new Thread(new Runnable(){
      public void run(){
        while(true){
          g.produce("商品");
        }
      }
    },"生产者一号").start();
    new Thread(new Runnable(){
      public void run(){
        while(true){
          g.produce("商品");
        }
      }
    },"生产者二号").start();
    new Thread(new Runnable(){
      public void run(){
        while(true){
          g.consume();
        }
      }
    },"消费者一号").start();
    new Thread(new Runnable(){
      public void run(){
        while(true){
          g.consume();
        }
      }
    },"消费者二号").start();
  }
}
/*
消费者二号消费了******商品编号:48049
生产者一号生产了....商品编号:48050
消费者一号消费了******商品编号:48050
生产者一号生产了....商品编号:48051
消费者二号消费了******商品编号:48051
生产者二号生产了....商品编号:48052
消费者二号消费了******商品编号:48052
生产者一号生产了....商品编号:48053
消费者一号消费了******商品编号:48053
生产者一号生产了....商品编号:48054
消费者二号消费了******商品编号:48054
生产者二号生产了....商品编号:48055
消费者二号消费了******商品编号:48055
*/
Copier après la connexion

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal