>  기사  >  Java  >  Java Thread 멀티스레딩 상세 설명 및 활용 분석

Java Thread 멀티스레딩 상세 설명 및 활용 분석

高洛峰
高洛峰원래의
2017-01-05 15:51:381601검색

Java 멀티스레딩 사용법에 대한 가장 포괄적인 분석입니다. Java의 멀티스레딩 메커니즘에 대한 심층적인 연구를 수행하지 않은 경우 이 기사는 Java 멀티스레딩의 원리와 사용법을 보다 철저하게 이해하는 데 도움이 될 수 있습니다.

1. 스레드 생성

Java에서 스레드를 생성하는 방법에는 Thread 클래스를 사용하는 방법과 Runnable 인터페이스를 사용하는 방법이 있습니다. Runnable 인터페이스를 사용하는 경우 Thread 인스턴스를 생성해야 합니다. 따라서 Thread 클래스를 통해 스레드를 생성하든 Runnable 인터페이스를 통해 생성하든 상관없이 Thread 클래스 또는 해당 하위 클래스의 인스턴스를 생성해야 합니다. 스레드 생성자:

public Thread( );

public Thread(실행 가능 대상);

public Thread(문자열 이름);

public Thread( Runnable 대상, 문자열 이름);

public Thread(ThreadGroup 그룹, 실행 가능 대상);

public Thread(ThreadGroup 그룹, 문자열 이름);

public Thread(ThreadGroup 그룹, 실행 가능한 대상, 문자열 이름);

public Thread(ThreadGroup 그룹, 실행 가능한 대상, 문자열 이름, 긴 stackSize);

방법 1: Thread 클래스를 상속하고 실행 메서드를 재정의합니다.

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

방법 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 클래스의 메서드를 통해 제어할 수 있습니다. Thread 클래스의 이 네 가지 상태와 관련된 메서드는 다음과 같습니다.

// 스레드 시작
publicvoid start( );
publicvoid run( );
// 스레드 일시 중지 및 깨우기
publicvoid 이력서( ) // 권장되지 않음
publicvoid suspens( ); // 사용을 권장하지 않습니다
publicstaticvoid sleep(long millis);
publicstaticvoid sleep(long millis, int nanos);
// 스레드 종료
publicvoid stop ( ); //
publicvoid Interrupt( );
// 스레드 상태 가져오기
publicboolean isAlive( );
publicboolean isInterrupted( );
publicstaticboolean Interrupted( )를 사용하는 것은 권장되지 않습니다. ;
// 조인 메소드
publicvoid Join() throws InterruptedException;

스레드가 실행 메소드의 코드를 확립한 직후에 실행하지 않고 대기 상태에 있습니다. . 스레드가 대기 상태일 때 Thread 클래스의 메소드를 통해 스레드의 우선순위(setPriority), 스레드 이름(setName), 스레드 유형(setDaemon) 등 스레드의 다양한 속성을 설정할 수 있습니다.

start 메소드가 호출되면 스레드는 run 메소드의 코드 실행을 시작합니다. 스레드가 실행 상태로 들어갑니다. Thread 클래스의 isAlive 메서드를 사용하여 스레드가 실행 중인지 확인할 수 있습니다. 스레드가 실행 중일 때 isAlive는 true를 반환합니다. isAlive가 false를 반환하면 스레드는 대기 상태이거나 중지된 상태일 수 있습니다. 다음 코드는 스레드 생성, 실행 및 중지의 세 가지 상태 간 전환을 보여주고 해당 isAlive 반환 값을 출력합니다.

스레드가 run 메소드 실행을 시작하면 run 메소드가 완료될 때까지 종료되지 않습니다. 그러나 스레드 실행 중에 두 가지 방법을 통해 스레드 실행을 일시적으로 중지할 수 있습니다. 이 두 가지 방법은 일시 중지 및 절전 모드입니다. Suspend를 사용하여 스레드를 일시 중단한 후, Resume 메소드를 통해 스레드를 깨울 수 있습니다. 스레드를 절전 모드로 만들기 위해 절전 모드를 사용한 후 스레드는 설정된 시간 이후에만 준비 상태에 있을 수 있습니다. (스레드 절전 모드가 끝난 후 스레드는 즉시 실행되지 않고 준비 상태로만 들어가 시스템의 일정을 기다립니다.) .

sleep 메서드를 사용할 때 주의할 점은 두 가지입니다.

1. sleep 메서드에는 두 가지 오버로드 형식이 있습니다. 오버로드된 형식 중 하나는 밀리초뿐만 아니라 나노초도 설정할 수 있습니다. 1,000,000나노초는 1밀리초와 같습니다). 그러나 대부분의 운영 체제 플랫폼의 JVM(Java Virtual Machine)은 나노초 단위로 정확하지 않습니다. 따라서 나노초가 절전 모드로 설정된 경우 JVM(Java Virtual Machine)은 이 값에 가장 가까운 밀리초를 사용합니다.

2. sleep 메서드를 사용할 때는 Throws 또는 try{…}catch{…}를 사용해야 합니다. run 메소드는 throw를 사용할 수 없으므로 try{...}catch{...}만 사용할 수 있습니다. 스레드가 휴면 상태이고 인터럽트 메서드를 사용하여 스레드를 중단하면 휴면 상태에서 InterruptedException이 발생합니다. sleep 메소드는 다음과 같이 정의됩니다.

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

세 가지 방법이 있습니다. 스레드를 종료합니다.

1. 스레드가 정상적으로 종료되도록 하려면 종료 플래그를 사용합니다. 즉, run 메서드가 완료되면 스레드가 종료됩니다.

2. 스레드를 강제로 종료하려면 stop 메소드를 사용하십시오. (이 메소드는 일시중단 및 재개와 마찬가지로 예상치 못한 결과를 초래할 수 있으므로 권장되지 않습니다.)

3. 스레드를 중단하려면 인터럽트 메서드를 사용하세요.

1. 종료 플래그를 사용하여 스레드를 종료합니다

当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中文网!


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.