Home  >  Article  >  Java  >  Java Thread multi-threading detailed explanation and usage analysis

Java Thread multi-threading detailed explanation and usage analysis

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

The most comprehensive analysis of Java multi-threading usage. If you have not done in-depth research on Java's multi-threading mechanism, this article can help you more thoroughly understand the principles and usage of Java multi-threading.

1. Create a thread

There are two ways to create a thread in Java: using the Thread class and using the Runnable interface. When using the Runnable interface, you need to create a Thread instance. Therefore, whether you create a thread through the Thread class or the Runnable interface, you must create an instance of the Thread class or its subclass. Thread constructor:

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

Method 1: Inherit the Thread class and override the run method

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

Method 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 life cycle

Just like people’s birth, old age, illness and death, threads also have to go through the four stages of starting (waiting), running, suspending and stopping. a different state. These four states can be controlled through methods in the Thread class. The methods related to these four states in the Thread class are given below.

// Start thread
publicvoid start( );
publicvoid run( );
// Suspend and wake up thread
publicvoid resume( ); // Not recommended
publicvoid suspend( ); // It is not recommended to use
publicstaticvoid sleep(long millis);
publicstaticvoid sleep(long millis, int nanos);
// Terminate the thread
publicvoid stop( ); // It is not recommended to use
publicvoid interrupt( );
// Get the thread status
publicboolean isAlive( );
publicboolean isInterrupted( );
publicstaticboolean interrupted( );
// join method
publicvoid join() throws InterruptedException;

The thread does not execute the code in the run method immediately after it is established, but is in a waiting state. When the thread is in the waiting state, you can set various attributes of the thread through the methods of the Thread class, such as the thread's priority (setPriority), thread name (setName), and thread type (setDaemon).

When the start method is called, the thread starts executing the code in the run method. The thread enters the running state. You can use the isAlive method of the Thread class to determine whether the thread is running. When the thread is in the running state, isAlive returns true. When isAlive returns false, the thread may be in the waiting state or in the stopped state. The following code demonstrates the switching between the three states of thread creation, running and stopping, and outputs the corresponding isAlive return value.

Once the thread starts executing the run method, it will not exit until the run method is completed. However, during the execution of the thread, there are two methods that can be used to temporarily stop the thread execution. These two methods are suspend and sleep. After using suspend to suspend a thread, you can wake it up through the resume method. After using sleep to make the thread sleep, the thread can only be in the ready state after the set time (after the thread sleep ends, the thread may not execute immediately, but only enters the ready state, waiting for the system to schedule).

There are two points to note when using the sleep method:

1. The sleep method has two overloaded forms. One of the overloaded forms can not only set milliseconds, but also set nanoseconds. (1,000,000 nanoseconds equals 1 millisecond). However, the Java virtual machine on most operating system platforms is not accurate to nanoseconds. Therefore, if nanoseconds are set for sleep, the Java virtual machine will take the millisecond closest to this value.

2. When using the sleep method, throws or try{…}catch{…} must be used. Because the run method cannot use throws, you can only use try{…}catch{…}. When the thread is sleeping and the interrupt method is used to interrupt the thread, sleep will throw an InterruptedException. The sleep method is defined as follows:

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

There are three ways to terminate the thread .

1. Use the exit flag to make the thread exit normally, that is, the thread terminates when the run method is completed.

2. Use the stop method to forcefully terminate the thread (this method is not recommended because stop, like suspend and resume, may also produce unpredictable results).

3. Use the interrupt method to interrupt the thread.

1. Terminate the thread using the 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中文网!


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn