Maison > Java > javaDidacticiel > Explication détaillée multithread Java Thread et analyse de l'utilisation

Explication détaillée multithread Java Thread et analyse de l'utilisation

高洛峰
Libérer: 2017-01-05 15:51:38
original
1650 Les gens l'ont consulté

L'analyse la plus complète de l'utilisation du multithreading Java. Si vous n'avez pas effectué de recherches approfondies sur le mécanisme multithread de Java, cet article peut vous aider à mieux comprendre les principes et l'utilisation du multithreading 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 cible, nom de la chaîne);

thread public (groupe ThreadGroup, cible Runnable);

thread public (groupe ThreadGroup, nom de la chaîne);

thread public (groupe ThreadGroup, Cible exécutable, nom de chaîne);

thread public (groupe ThreadGroup, cible exécutable, nom de chaîne, long stackSize);

Méthode 1 : hériter de la classe Thread et remplacer la méthode d'exécution

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. Cycle de vie des fils

Tout comme la naissance, la vieillesse, la maladie et la mort des gens, les fils doivent aussi passer par démarrage (attente), exécution et suspension. Il existe quatre états différents de démarrage et d'arrêt. 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.

// Démarrer le fil
publicvoid start( );
publicvoid run( );
// Suspendre et réveiller le fil
publicvoid curriculum vitae( ); // Non recommandé< 🎜); >publicvoid suspend( ); // Il n'est pas recommandé d'utiliser
publicstaticvoid sleep(long millis);
publicstaticvoid sleep(long millis, int nanos);
// Terminer le fil
publicvoid stop ( ); // Il n'est pas recommandé d'utiliser
publicvoid interrompu( );
// Obtenir l'état du fil
publicboolean isAlive( );
publicboolean isInterrupted( );
publicstaticboolean interrompu( ) ;
// join method
publicvoid join() throws InterruptedException;

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

Il existe trois façons de terminer un fil de discussion.

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. Terminez le fil de discussion à l'aide de l'indicateur de sortie

当run方法执行完后,线程就会退出。但有时run方法是永远不会结束的。如在服务端程序中使用线程进行监听客户端请求,或是其他的需要循环处理的任务。在这种情况下,一般是将这些任务放在一个循环中,如while循环。如果想让循环永远运行下去,可以使用while(true){…}来处理。但要想使while循环在某一特定条件下退出,最直接的方法就是设一个boolean类型的标志,并通过设置这个标志为true或false来控制while循环是否退出。下面给出了一个利用退出标志终止线程的例子。

join方法的功能就是使异步执行的线程变成同步执行。也就是说,当调用线程实例的start方法后,这个方法会立即返回,如果在调用start方法后后需要使用一个由这个线程计算得到的值,就必须使用join方法。如果不使用join方法,就不能保证当执行到start方法后面的某条语句时,这个线程一定会执行完。而使用join方法后,直到这个线程退出,程序才会往下执行。下面的代码演示了join的用法。

3.多线程安全问题

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

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

同步代码块:

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

以上就是对Java 多线程的资料整理,后续继续补充相关知识,谢谢大家对本站的支持!

更多Java Thread多线程详解及用法解析相关文章请关注PHP中文网!


É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