26_多線程_第26天(Thread、線程建立、線程池)_講義

今日內容介紹
一、多線程
二、線程池java

01進程概念

A:進程概念多線程

a:進程:進程指正在運行的程序。確切的來講,當一個程序進入內存運行,併發

即變成一個進程,進程是處於運行過程當中的程序,而且具備必定獨立功能。異步

02線程的概念

A:線程的概念jvm

a:線程:線程是進程中的一個執行單元(執行路徑),負責當前進程中程序的執行,編輯器

一個進程中至少有一個線程。一個進程中是能夠有多個線程的,函數

這個應用程序也能夠稱之爲多線程程序。學習

簡而言之:一個程序運行後至少有一個進程,一個進程中能夠包含多個線程

03深刻線程的概念

A:深刻線程的概念測試

什麼是多線程呢?this

即就是一個程序中有多個線程在同時執行。

一個核心的CPU在多個線程之間進行着隨即切換動做,因爲切換時間很短(毫秒甚至是納秒級別),致使咱們感受不出來

單線程程序:即,如有多個任務只能依次執行。當上一個任務執行結束後,下一個任務開始執行。如去 網吧上網,網吧只能讓一我的上網,當這我的下機後,下一我的才能上網。

多線程程序:

即,如有多個任務能夠同時執行。如,去網吧上網,網吧可以讓多我的同時上網。

04迅雷的多線程下載

A:迅雷的多線程下載

多線程,每一個線程都讀一個文件

05線程的運行模式

A:線程的運行模式

a:分時調度

全部線程輪流使用 CPU 的使用權,平均分配每一個線程佔用 CPU 的時間。

b:搶佔式調度

優先讓優先級高的線程使用 CPU,若是線程的優先級相同,那麼會隨機選擇一個(線程隨機性),
Java使用的爲搶佔式調度。

大部分操做系統都支持多進程併發運行,如今的操做系統幾乎都支持同時運行多個程序。好比:
如今咱們上課一邊使用編輯器,一邊使用錄屏軟件,同時還開着畫圖板,dos窗口等軟件。
此時,這些程序是在同時運行,」感受這些軟件好像在同一時刻運行着「。

實際上,CPU(中央處理器)使用搶佔式調度模式在多個線程間進行着高速的切換。
對於CPU的一個核而言,某個時刻,只能執行一個線程,而 CPU的在多個線程間切換速度
相對咱們的感受要快,看上去就是在同一時刻運行。
其實,多線程程序並不能提升程序的運行速度,但可以提升程序運行效率,讓CPU的使用率更高。

06main的主線程

A:main的主線程

/*
 *  程序中的主線程
 */
public class Demo {
  public static void main(String[] args) {
    System.out.println(0/0);
    function();
    System.out.println(Math.abs(-9));
  }
  
  public static void function(){
    for(int i = 0 ; i < 10000;i++){
      System.out.println(i);
    }
  }
}

07Thread類介紹

A:Thread類介紹:

Thread是程序中的執行線程。Java 虛擬機容許應用程序併發地運行多個執行線程。

發現建立新執行線程有兩種方法

a:一種方法是將類聲明爲 Thread 的子類。該子類應重寫 Thread 類的 run 方法。建立對象,開啓線程。run方法至關於其餘線程的main方法。

b:另外一種方法是聲明一個實現 Runnable 接口的類。該類而後實現 run 方法。而後建立Runnable的子類對象,傳入到某個線程的構造方法中,開啓線程。

08實現線程程序繼承Thread

*A:實現線程程序繼承Thread

/*
   * 建立和啓動一個線程
   *   建立Thread子類對象
   *   子類對象調用方法start()
   *      讓線程程序執行,JVM調用線程中的run
   */
  public class ThreadDemo {
    public static void main(String[] args) {
      SubThread st = new SubThread();
      SubThread st1 = new SubThread();
      st.start();
      st1.start();
      for(int i = 0; i < 50;i++){
        System.out.println("main..."+i);
      }
    }
  }
  /*
   *  定義子類,繼承Thread 
   *  重寫方法run 
   */
  public class SubThread  extends Thread{
    public void run(){
      for(int i = 0; i < 50;i++){
        System.out.println("run..."+i);
      }
    }
  }

09線程執行的隨機性

A:線程執行的隨機性

/*
  代碼分析:
     整個程序就只有三個線程,
     一個是主線程
       啓動另外兩個線程
        st.start();
        st1.start();
        for(int i = 0; i < 50;i++){
          System.out.println("main..."+i);
        }
     一個是st(Thread-0)線程
     for(int i = 0; i < 50;i++){
       System.out.println("run..."+i);
     }
     一個是st1(Thread-1)線程下 

*/
 public class ThreadDemo {
   public static void main(String[] args) {
     SubThread st = new SubThread();
     SubThread st1 = new SubThread();
     st.start();
     st1.start();
     for(int i = 0; i < 50;i++){
       System.out.println("main..."+i);
     }
   }
 }
 /*
  *  定義子類,繼承Thread 
  *  重寫方法run 
  */
 public class SubThread  extends Thread{
   public void run(){
     for(int i = 0; i < 50;i++){
       System.out.println("run..."+i);
     }
   }
 }

10爲何要繼承Thread

A:什麼要繼承Thread

a:咱們爲何要繼承Thread類,並調用其的start方法才能開啓線程呢?

   繼承Thread類:由於Thread類用來描述線程,具有線程應該有功能。那爲何不直接建立Thread類的對象呢?
   以下代碼:
    Thread t1 = new Thread();
    t1.start();//這樣作沒有錯,可是該start調用的是Thread類中的run方法
              //而這個run方法沒有作什麼事情,更重要的是這個run方法中並無定義咱們須要讓線程執行的代碼。

b:建立線程的目的是什麼?

 是爲了創建程序單獨的執行路徑,讓多部分代碼實現同時執行。也就是說線程建立並執行須要給定線程要執行的任務。
 對於以前所講的主線程,它的任務定義在main函數中。自定義線程須要執行的任務都定義在run方法中。

11多線程內存圖解

A:多線程內存圖解

多線程執行時,到底在內存中是如何運行的呢?

多線程執行時,在棧內存中,其實每個執行線程都有一片本身所屬的棧內存空間。進行方法的壓棧和彈棧。
當執行線程的任務結束了,線程自動在棧內存中釋放了。可是當全部的執行線程都結束了,那麼進程就結束了。

12獲取線程名字Thread類方法getName

A:獲取線程名字Thread類方法getName

/*
 *  獲取線程名字,父類Thread方法
 *    String getName()
 */
public class NameThread extends Thread{
  
  public NameThread(){
    super("小強");
  }
  
  public void run(){
    System.out.println(getName());
  }
}

/*
 *  每一個線程,都有本身的名字
 *  運行方法main線程,名字就是"main"
 *  其餘新鍵的線程也有名字,默認 "Thread-0","Thread-1"
 *  
 *  JVM開啓主線程,運行方法main,主線程也是線程,是線程必然就是
 *  Thread類對象
 */
public class ThreadDemo {
  public static void main(String[] args) {
    NameThread nt = new NameThread();
    nt.start();  
  }
}

13獲取線程名字Thread類方法currentThread

A:獲取線程名字Thread類方法currentThread

/*
    *  獲取線程名字,父類Thread方法
    *    String getName()
    */
   public class NameThread extends Thread{

     public void run(){
       System.out.println(getName());
     }
   }
   
   /*
    *  每一個線程,都有本身的名字
    *  運行方法main線程,名字就是"main"
    *  其餘新鍵的線程也有名字,默認 "Thread-0","Thread-1"
    *  
    *  JVM開啓主線程,運行方法main,主線程也是線程,是線程必然就是
    *  Thread類對象
    *  Thread類中,靜態方法
    *   static Thread currentThread()返回正在執行的線程對象
    */
   public class ThreadDemo {
     public static void main(String[] args) {
       NameThread nt = new NameThread();
       nt.start();
       
       /*Thread t =Thread.currentThread();
       System.out.println(t.getName());*/
       System.out.println(Thread.currentThread().getName());
     }
   }

14線程名字設置

A:線程名字設置

/*
   *  獲取線程名字,父類Thread方法
   *    String getName()
   */
  public class NameThread extends Thread{
    
    public NameThread(){
      super("小強");
    }
    
    public void run(){
      System.out.println(getName());
    }
  }
  
  /*
   *  每一個線程,都有本身的名字
   *  運行方法main線程,名字就是"main"
   *  其餘新鍵的線程也有名字,默認 "Thread-0","Thread-1"
   *  
   *  JVM開啓主線程,運行方法main,主線程也是線程,是線程必然就是
   *  Thread類對象
   *  Thread類中,靜態方法
   *   static Thread currentThread()返回正在執行的線程對象
   */
  public class ThreadDemo {
    public static void main(String[] args) {
      NameThread nt = new NameThread();
      nt.setName("旺財");
      nt.start();
    }
  }

15Thread類方法sleep

A:Thread類方法sleep

public class ThreadDemo {
  public static void main(String[] args) throws Exception{
    /*for(int i = 0 ; i < 5 ;i++){
      Thread.sleep(50);
      System.out.println(i);
    }*/
    
    new SleepThread().start();
  }
 }
 
 public class SleepThread extends Thread{
  public void run(){
    for(int i = 0 ; i < 5 ;i++){
      try{
        Thread.sleep(500);//睡眠500ms,500ms已到而且cpu切換到該線程繼續向下執行
      }catch(Exception ex){
        
      }
      System.out.println(i);
    }
  }
 }

16實現線程的另外一種方式實現Runnable接口

A:實現線程的另外一種方式實現Runnable接口

/*
  *  實現接口方式的線程
  *    建立Thread類對象,構造方法中,傳遞Runnable接口實現類
  *    調用Thread類方法start()
  */
 public class ThreadDemo {
  public static void main(String[] args) {
    SubRunnable sr = new SubRunnable();
    Thread t = new Thread(sr);
    t.start();
    for(int i = 0 ; i < 50; i++){
      System.out.println("main..."+i);
    }
  }
 }

 /*
  *  實現線程成功的另外一個方式,接口實現
  *  實現接口Runnable,重寫run方法
  */
 public class SubRunnable implements Runnable{
  public void run(){
    for(int i = 0 ; i < 50; i++){
      System.out.println("run..."+i);
    }
  }
 }

17實現接口方式的好處

A:實現接口方式的好處

第二種方式實現Runnable接口避免了單繼承的侷限性,因此較爲經常使用。

 實現Runnable接口的方式,更加的符合面向對象,線程分爲兩部分,一部分線程對象,一部分線程任務。
 繼承Thread類,線程對象和線程任務耦合在一塊兒。

 一旦建立Thread類的子類對象,既是線程對象,有又有線程任務。

 實現runnable接口,將線程任務單獨分離出來封裝成對象,類型就是Runnable接口類型。Runnable接口對線程對象和線程任務進行解耦。

 (下降緊密性或者依賴性,建立線程和執行任務不綁定)

18匿名內部類實現線程程序

A:匿名內部類實現線程程序

/*
 *  使用匿名內部類,實現多線程程序
 *  前提: 繼承或者接口實現
 *  new 父類或者接口(){
 *     重寫抽象方法
 *  }
 */
public class ThreadDemo {
  public static void main(String[] args) {
    //繼承方式  XXX extends Thread{ public void run(){}}
    new Thread(){
      public void run(){
        System.out.println("!!!");
      }
    }.start();
    
    //實現接口方式  XXX implements Runnable{ public void run(){}}
    
    Runnable r = new Runnable(){
      public void run(){
        System.out.println("###");
      }
    };
    new Thread(r).start();
    
    
    new Thread(new Runnable(){
      public void run(){
        System.out.println("@@@");
      }
    }).start();
    
  }
}

19線程的狀態圖

A:線程的狀態圖

20線程池的原理

A:線程池的原理

1.在java中,若是每一個請求到達就建立一個新線程,開銷是至關大的。
  2.在實際使用中,建立和銷燬線程花費的時間和消耗的系統資源都至關大
    ,甚至可能要比在處理實際的用戶請求的時間和資源要多的多。
  3.除了建立和銷燬線程的開銷以外,活動的線程也須要消耗系統資源。
    若是在一個jvm裏建立太多的線程,可能會使系統因爲過分消耗內存或「切換過分」而致使系統資
    源不足。
    爲了防止資源不足,須要採起一些辦法來限制任何給定時刻處理的請求數目,儘量減小創
    建和銷燬線程的次數,特別是一些資源耗費比較大的線程的建立和銷燬,儘可能利用已有對象來進行服務。
  線程池主要用來解決線程生命週期開銷問題和資源不足問題。經過對多個任務重複使用線程
    ,線程建立的開銷就被分攤到了多個任務上了,並且因爲在請求到達時線程已經存在
    ,因此消除了線程建立所帶來的延遲。這樣,就能夠當即爲請求服務,使用應用程序響應更快。另
    外,經過適當的調整線程中的線程數目能夠防止出現資源不足的狀況。

21JDK5實現線程池

A:JDK5實現線程池

/*
   *  JDK1.5新特性,實現線程池程序
   *  使用工廠類 Executors中的靜態方法建立線程對象,指定線程的個數
   *   static ExecutorService newFixedThreadPool(int 個數) 返回線程池對象
   *   返回的是ExecutorService接口的實現類 (線程池對象)
   *   
   *   接口實現類對象,調用方法submit (Ruunable r) 提交線程執行任務
   *          
   */
  public class ThreadPoolDemo {
    public static void main(String[] args) {
      //調用工廠類的靜態方法,建立線程池對象
      //返回線程池對象,是返回的接口
      ExecutorService es = Executors.newFixedThreadPool(2);
        //調用接口實現類對象es中的方法submit提交線程任務
      //將Runnable接口實現類對象,傳遞
      es.submit(new ThreadPoolRunnable());
      es.submit(new ThreadPoolRunnable());
      es.submit(new ThreadPoolRunnable());
    
    }
  }

  public class ThreadPoolRunnable implements Runnable {
    public void run(){
      System.out.println(Thread.currentThread().getName()+" 線程提交任務");
    }
  }

22實現線程的Callable接口方式

A:實現線程的Callable接口方式

/*
  *  實現線程程序的第三個方式,實現Callable接口方式
  *  實現步驟
  *    工廠類 Executors靜態方法newFixedThreadPool方法,建立線程池對象
  *    線程池對象ExecutorService接口實現類,調用方法submit提交線程任務
  *    submit(Callable c)
  */
 public class ThreadPoolDemo1 {
  public static void main(String[] args)throws Exception {
    ExecutorService es = Executors.newFixedThreadPool(2);
    //提交線程任務的方法submit方法返回 Future接口的實現類
    Future<String> f = es.submit(new ThreadPoolCallable());
    String s = f.get();
    System.out.println(s);
  }
 }
 /*
  * Callable 接口的實現類,做爲線程提交任務出現
  * 使用方法返回值
  */

 import java.util.concurrent.Callable;

 public class ThreadPoolCallable implements Callable<String>{
  public String call(){
    return "abc";
  }
 }

23線程實現異步計算

A:線程實現異步計算

/*
 * 使用多線程技術,求和
 * 兩個線程,1個線程計算1+100,另外一個線程計算1+200的和
 * 多線程的異步計算
 */
public class ThreadPoolDemo {
  public static void main(String[] args)throws Exception {
    ExecutorService es = Executors.newFixedThreadPool(2);
    Future<Integer> f1 =es.submit(new GetSumCallable(100));
    Future<Integer> f2 =es.submit(new GetSumCallable(200));
    System.out.println(f1.get());
    System.out.println(f2.get());
    es.shutdown();
  }
}



public class GetSumCallable implements Callable<Integer>{
  private int a;
  public GetSumCallable(int a){
    this.a=a;
  }
  
  public Integer call(){
    int sum = 0 ;
    for(int i = 1 ; i <=a ; i++){
      sum = sum + i ;
    }
    return sum;
  }
}

做業測試

1.進程與線程的關係

2.多線程兩種實現方式

3.多線程兩種實現方式的區別

4.線程池的原理

4.線程的生命週期

若是想進一步的交流,能夠加入咱們的QQ羣,裏面有最新的學習資料,能夠學習。

相關文章
相關標籤/搜索