首頁 > Java > java教程 > 主體

Java中使用三種建構多執行緒的方法來分享

黄舟
發布: 2017-09-18 09:37:35
原創
1371 人瀏覽過

這篇文章主要介紹了java  多線程的三種構建方法的相關資料,這裡提供三種實現方法,希望大家能夠掌握,很重要的基礎知識,需要的朋友可以參考下

java  多執行緒的三種建置方法

繼承Thread類別建立執行緒類別


public class Thread extends Object implements Runnable
登入後複製
  1. 定義Thread類別的子類,並重寫其run()方法

  2. #建立Thread子類別的實例,即建立了執行緒物件

  3. 呼叫執行緒物件的start()方法啟動執行緒


#
public class FirstThread extends Thread {
  public void run(){
    for(int i=0;i<100;i++){
      /*
       * Thread类已经继承了Object
       * Object类创建了name选项 并且有其getName(),setName()方法
       * 在继承Thread的类里面使用时只需要用this引用
      */
      System.out.println(this.getName()+" "+i);
    }
  }

  public static void main(String[] args) {
    for(int i=0;i<100;i++){
      System.out.println(Thread.currentThread().getName()+" "+i);
      if(i==20){
        new FirstThread().start();
        new FirstThread().start();
      }
    }
  }

}
登入後複製

Thread類別已經繼承了Object

Object類別建立了name選項並且有其getName(),setName()方法

#在繼承Thread的類別裡面使用時只需要用this引用

上面兩個副線程和主線程隨機切換,又因為使用的是繼承Thread的類別所以兩個副線程不能共享資源

start()方法調用後並不是立即執行多線程程式碼,而是使得該執行緒程式設計可運行狀態,何時運行是由作業系統決定的

#實作Runnable介面建立執行緒類別


#
public Thread() 
public Thread(Runnable target) 
public Thread(Runnable target,String name)
登入後複製
  • 定義Runnable介面的實作類,並重寫該介面的run()方法

  • 建立Runnable實作類的實例,並以此作為Thread的target來創建Thread對象,該Thread對象才是真正的線程對象。


public class SecondThread implements Runnable {
  public void run(){
    for(int i=0;i<100;i++){
      System.out.println(Thread.currentThread().getName()+" "+i);
    }
  }

  public static void main(String[] args) {
    for(int i=0;i<100;i++){
      System.out.println(Thread.currentThread().getName()+" "+i);

      if(i==20){
        SecondThread st=new SecondThread();
        //通过new Thread(target,name)创建线程
        new Thread(st,"新线程1").start();
        new Thread(st,"新线程2").start();
      }
    }
  }
}
登入後複製

上面的結果是兩個副執行緒和主執行緒隨機切換,但是並沒有共享資源,因為他們根本沒有能用來共享的資源。

start()方法呼叫後並不是立即執行多執行緒程式碼,而是使得該執行緒程式設計可運行狀態,什麼時候運行是由作業系統決定的
繼承Thread類別和創建Runnable介面的共享資源詳解

在只有可以用來共享的資源時候,也就是同用一個實例化物件。兩個建立方式在共享資源時才會有所區別,否則它們都不會共享資源共享資源通常用private static 修飾符來修飾。


class Thread1 extends Thread{ 
  private int count=5; 
  private String name; 
  public Thread1(String name) { 
    this.name=name; 
  } 
  public void run() { 
    for (int i = 0; i < 5; i++) { 
      System.out.println(name + "运行 count= " + count--); 
      try { 
        sleep((int) Math.random() * 10); 
      } catch (InterruptedException e) { 
        e.printStackTrace(); 
      } 
    } 

  } 
} 

public class Main { 

  public static void main(String[] args) { 
    Thread1 mTh1=new Thread1("A"); 
    Thread1 mTh2=new Thread1("B"); 
    mTh1.start(); 
    mTh2.start(); 

  } 

}
登入後複製


B运行 count= 5 
A运行 count= 5 
B运行 count= 4 
B运行 count= 3 
B运行 count= 2 
B运行 count= 1 
A运行 count= 4 
A运行 count= 3 
A运行 count= 2 
A运行 count= 1
登入後複製

正是因為有了private int count=5;一句才有了共享資源,但這是繼承Thread類的子類,並不能共享資源


class Thread2 implements Runnable{ 
  private int count=15; 
  public void run() { 
     for (int i = 0; i < 5; i++) { 
       System.out.println(Thread.currentThread().getName() + "运行 count= " + count--); 
        try { 
          Thread.sleep((int) Math.random() * 10); 
        } catch (InterruptedException e) { 
          e.printStackTrace(); 
        } 
      } 

  } 

} 
public class Main { 

  public static void main(String[] args) { 

    Thread2 my = new Thread2(); 
      new Thread(my, "C").start();//同一个mt,但是在Thread中就不可以,如果用同一个实例化对象mt,就会出现异常   
      new Thread(my, "D").start(); 
      new Thread(my, "E").start(); 
  } 

}
登入後複製


C运行 count= 15 
D运行 count= 14 
E运行 count= 13 
D运行 count= 12 
D运行 count= 10 
D运行 count= 9 
D运行 count= 8 
C运行 count= 11 
E运行 count= 12 
C运行 count= 7 
E运行 count= 6 
C运行 count= 5 
E运行 count= 4 
C运行 count= 3 
E运行 count= 2
登入後複製

同樣的正是因為有了private int count=15這個共同的實例化對象,實作Runnable的類別才可以共享資源

那為什麼繼承Thread類別的子類別實作Runable介面的類別在共享資源時有差別呢?

因為Java只能支援單繼承,單繼承特點意味著只能有一個子類去繼承而Runnabl接口後可以跟好多類,便可以進行多個線程共享一個資源的操作

使用Callable和Future建立執行緒

#Callable怎麼看起來都像Runnable介面的增強版,Callable有一個call()方法相當於Runnable的run()方法,但是功能更加強大:

call()方法可以有回傳值
call()方法可以宣告拋出例外

Callable介面有泛型限制,Callable介面裡的泛型形參類型與call()方法的回傳值類型相同。 而且Callable介面是函數式接口,因此可使用Lambda表達式建立Callable物件Runnable介面也是函數式接口,因此也可以使用Lambda表達式建立Runnable物件

  1. #建立Callable介面的實作類,並實作call()方法,該call()方法將作為執行緒執行體,再建立Callable實作類別的實例

使用FutureTask類別來包裝Callable對象,FutureTask物件封裝了該Callable物件的call()方法


使用FutureTask類別物件作為Thread物件的target建立並啟動新執行緒

呼叫FutureTask物件的get()方法來取得子執行緒結束後的回傳值

###############
public class ThirdThread implements Callable<Integer> {
  public Integer call(){
    int i=0;
    for(;i<100;i++){
      System.out.println(Thread.currentThread().getName()+" "+i);
    }
    return i;
  }

  public static void main(String[] args){
    ThirdThread tt=new ThirdThread();
    FutureTask<Integer> task=new FutureTask<>(tt);
    Thread t=new Thread(task,"有返回值的线程");
    for(int i=0;i<100;i++){
      System.out.println(Thread.currentThread().getName()+" "+i);
      if(i==20){
        t.start();
      }
    }
    try{
      System.out.println("返回值是:"+task.get());
    }catch(Exception e){
      e.printStackTrace();
    }
  }
}
登入後複製
######使用Lambda表達式的Callable和Future建立的執行緒###############
public class ThirdThread{
  public static void main(String[] args){
    ThirdThread tt=new ThirdThread();
    //先使用Lambda表达式创建Callable<Integer>对象
    //使用FutureTask封装Callable对象
    FutureTask<Integer> task=new FutureTask<Integer>((Callable<Integer>)()->{
      int i=0;
      for(;i<100;i++){
        System.out.println(Thread.currentThread().getName()+"的循环变量i的值:"+i);
      }
      return i;
    });

    for(int i=0;i<100;i++){
      System.out.println(Thread.currentThread().getName()+"的循环变量i的值:"+i);
      if(i==20){
        new Thread(task,"有返回值的线程").start();
      }
    }
    try{
      System.out.println("子线程的返回值"+task.get());
    }catch(Exception e){
      e.printStackTrace();
    }
  }
}
登入後複製

以上是Java中使用三種建構多執行緒的方法來分享的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板