Heim  >  Artikel  >  Java  >  Detaillierte Erklärung und Nutzungsanalyse von Java Thread Multithreading

Detaillierte Erklärung und Nutzungsanalyse von Java Thread Multithreading

高洛峰
高洛峰Original
2017-01-05 15:51:381564Durchsuche

Die umfassendste Analyse der Java-Multithreading-Nutzung. Wenn Sie den Multithreading-Mechanismus von Java noch nicht eingehend untersucht haben, kann Ihnen dieser Artikel dabei helfen, die Prinzipien und die Verwendung von Java-Multithreading besser zu verstehen.

1. Erstellen Sie einen Thread

Es gibt zwei Möglichkeiten, einen Thread in Java zu erstellen: mithilfe der Thread-Klasse und mithilfe der Runnable-Schnittstelle. Wenn Sie die Runnable-Schnittstelle verwenden, müssen Sie eine Thread-Instanz erstellen. Unabhängig davon, ob Sie einen Thread über die Thread-Klasse oder die Runnable-Schnittstelle erstellen, müssen Sie daher eine Instanz der Thread-Klasse oder ihrer Unterklasse erstellen. Thread-Konstruktor:

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 , Ausführbares Ziel, String-Name);

öffentlicher Thread(ThreadGroup-Gruppe, ausführbares Ziel, String-Name, lange Stapelgröße);

Methode 1: Erben Sie die Thread-Klasse und überschreiben Sie die Ausführungsmethode

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);
   }
  }
 }

Methode 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);
  }
 }
}

2. Thread-Lebenszyklus

Genau wie Geburt, Alter, Krankheit und Tod von Menschen müssen auch Threads durchlaufen Starten (Warten), Laufen und Hängen. Es gibt vier verschiedene Start- und Stoppzustände. Diese vier Zustände können durch Methoden in der Thread-Klasse gesteuert werden. Die Methoden, die sich auf diese vier Zustände in der Thread-Klasse beziehen, sind unten aufgeführt.

// Thread starten
publicvoid start( );
publicvoid run( );
// Thread anhalten und aktivieren
publicvoid resume( ); // Nicht empfohlen
publicvoid suspend( ); // Es wird nicht empfohlen,
publicstaticvoid sleep(long millis);
publicstaticvoid sleep(long millis, int nanos);
// Beenden Sie den Thread
publicvoid stop ( ); // Es wird nicht empfohlen,
publicvoid interrupt( );
// Thread-Status abrufen
publicboolean isAlive( );
publicboolean isInterrupted( );
publicstaticboolean interrupted( ) ;
// Join-Methode
publicvoid join() throws InterruptedException;

Der Thread führt den Code in der Run-Methode nicht unmittelbar nach seiner Einrichtung aus, sondern befindet sich im Wartezustand . Wenn sich der Thread im Wartezustand befindet, können Sie über die Methoden der Thread-Klasse verschiedene Attribute des Threads festlegen, z. B. die Priorität des Threads (setPriority), den Thread-Namen (setName) und den Thread-Typ (setDaemon).

Wenn die Startmethode aufgerufen wird, beginnt der Thread mit der Ausführung des Codes in der Run-Methode. Der Thread wechselt in den laufenden Zustand. Sie können die isAlive-Methode der Thread-Klasse verwenden, um festzustellen, ob der Thread ausgeführt wird. Wenn sich der Thread im laufenden Zustand befindet, gibt isAlive „true“ zurück. Wenn isAlive „false“ zurückgibt, befindet sich der Thread möglicherweise im Wartezustand oder im gestoppten Zustand. Der folgende Code demonstriert den Wechsel zwischen den drei Zuständen Thread-Erstellung, Ausführung und Stopp und gibt den entsprechenden isAlive-Rückgabewert aus.

Sobald ein Thread mit der Ausführung der Ausführungsmethode beginnt, wird er nicht beendet, bis die Ausführungsmethode abgeschlossen ist. Während der Ausführung des Threads können Sie die Thread-Ausführung jedoch über zwei Methoden vorübergehend stoppen. Diese beiden Methoden sind Suspend und Sleep. Nachdem Sie einen Thread mit Suspend angehalten haben, können Sie ihn über die Resume-Methode aktivieren. Nachdem Sie Sleep verwendet haben, um den Thread in den Ruhezustand zu versetzen, kann sich der Thread erst nach der festgelegten Zeit im Bereitschaftszustand befinden (nachdem der Thread-Ruhezustand endet, wird der Thread möglicherweise nicht sofort ausgeführt, sondern wechselt nur in den Bereitschaftszustand und wartet auf die Planung durch das System). .

Bei der Verwendung der Schlafmethode sind zwei Punkte zu beachten:

1. Eine der überladenen Formen kann nicht nur Millisekunden, sondern auch Nanosekunden festlegen. 1.000.000 Nanosekunden entsprechen 1 Millisekunde. Allerdings ist die Java Virtual Machine auf den meisten Betriebssystemplattformen nicht auf Nanosekunden genau. Wenn daher Nanosekunden für den Ruhezustand eingestellt sind, verwendet die Java Virtual Machine die Millisekunde, die diesem Wert am nächsten kommt.

2. Bei Verwendung der Schlafmethode müssen Würfe oder Versuche{…}Fänge{…} verwendet werden. Da die run-Methode keine Würfe verwenden kann, können Sie nur try{…}catch{…} verwenden. Wenn der Thread schläft und die Interrupt-Methode zum Unterbrechen des Threads verwendet wird, löst Sleep eine InterruptedException aus. Die Schlafmethode ist wie folgt definiert:

publicstaticvoid sleep(long millis) throws InterruptedException
publicstaticvoid sleep(long millis, int nanos) throws InterruptedException

Es gibt drei Möglichkeiten dazu Einen Thread beenden.

1. Verwenden Sie das Exit-Flag, um den Thread normal zu beenden, dh der Thread wird beendet, wenn die Ausführungsmethode abgeschlossen ist.

2. Verwenden Sie die Stop-Methode, um den Thread zwangsweise zu beenden (diese Methode wird nicht empfohlen, da das Stoppen ebenso wie das Anhalten und Fortsetzen zu unvorhersehbaren Ergebnissen führen kann).

3. Verwenden Sie die Interrupt-Methode, um den Thread zu unterbrechen.

1. Beenden Sie den Thread mit dem Exit-Flag

当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--);
   }
  }
 }
}

同步函数

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();
  }
 }
}

同步函数锁是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....男
*/

修改上面代码

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
 张三....男
 张三....男
 张三....男
 张三....男
 */

等待唤醒机制

/*
 *线程等待唤醒机制
 *等待和唤醒必须是同一把锁 
 */
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();
 }
}

生产消费机制一

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();
 }
}

生产消费机制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
*/

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

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


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn