多線程相關知識點

多線程技術概述

線程與進程

進程
是指一個內存中運行的應用程序,每個進程都有一個獨立的內存空間

線程

  • 是進程中的一個執(zhí)行路徑,共享一個內存空間,線程之間可以自由切換,并發(fā)執(zhí)行. 一個進程最少有一個線程
  • 線程實際上是在進程基礎之上的進一步劃分,一個進程啟動之后,里面的若干執(zhí)行路徑又可以劃分成若干個線程

線程調度

分時調度
所有線程輪流使用 CPU 的使用權,平均分配每個線程占用 CPU 的時間。

搶占式調度

  • 優(yōu)先讓優(yōu)先級高的線程使用 CPU,如果線程的優(yōu)先級相同,那么會隨機選擇一個(線程隨機性)
    Java使用的為搶占式調度
  • CPU使用搶占式調度模式在多個線程間進行著高速的切換。對于CPU的一個核新而言,某個時刻,只能執(zhí)行一個線程,而 CPU的在多個線程間切換速度相對我們的感覺要快,看上去就是 在同一時刻運行。 其實多線程程序并不能提高程序的運行速度,但能夠提高程序運行效率,讓CPU的 使用率更高。

同步與異步

  • 同步:排隊執(zhí)行 , 效率低但是安全.
  • 異步:同時執(zhí)行 , 效率高但是數據不安全.

并發(fā)與并行

  • 并發(fā):指兩個或多個事件在同一個時間段內發(fā)生。
  • 并行:指兩個或多個事件在同一時刻發(fā)生(同時發(fā)生)

線程池 Executors

如果并發(fā)的線程數量很多,并且每個線程都是執(zhí)行一個時間很短的任務就結束了,這樣頻繁創(chuàng)建線程就會大大降低 系統(tǒng)的效率,因為頻繁創(chuàng)建線程和銷毀線程需要時間. 線程池就是一個容納多個線程的容器,池中的線程可以反復使用,省去了頻繁創(chuàng)建線程對象的操作,節(jié)省了大量的時間和資源。

線程池的好處

  • 降低資源消耗。
  • 提高響應速度。
  • 提高線程的可管理性。

Java中的四種線程池 . ExecutorService

1. 緩存線程池

/**
* 緩存線程池.
* (長度無限制)
* 執(zhí)行流程:
* 1. 判斷線程池是否存在空閑線程
* 2. 存在則使用
* 3. 不存在,則創(chuàng)建線程 并放入線程池, 然后使用
*/
ExecutorService service = Executors.newCachedThreadPool();
//向線程池中 加入 新的任務
service.execute(new Runnable() {
  @Override
  public void run() {
    System.out.println("線程的名稱:"+Thread.currentThread().getName());
  }
});
service.execute(new Runnable() {
  @Override
  public void run() {
    System.out.println("線程的名稱:"+Thread.currentThread().getName());
  }
});
service.execute(new Runnable() {
   @Override
  public void run() {
    System.out.println("線程的名稱:"+Thread.currentThread().getName());
  }
});

2. 定長線程池

/**
* 定長線程池.
* (長度是指定的數值)
* 執(zhí)行流程:
* 1. 判斷線程池是否存在空閑線程
* 2. 存在則使用
* 3. 不存在空閑線程,且線程池未滿的情況下,則創(chuàng)建線程 并放入線程池, 然后使用
* 4. 不存在空閑線程,且線程池已滿的情況下,則等待線程池存在空閑線程
*/
ExecutorService service = Executors.newFixedThreadPool(2);
service.execute(new Runnable() {
  @Override
  public void run() {
    System.out.println("線程的名稱:"+Thread.currentThread().getName());
  }
});
service.execute(new Runnable() {
  @Override
  public void run() {
    System.out.println("線程的名稱:"+Thread.currentThread().getName());
  }
});

3. 單線程線程池
效果與定長線程池 創(chuàng)建時傳入數值1 效果一致.

/**
* 單線程線程池.
* 執(zhí)行流程:
* 1. 判斷線程池 的那個線程 是否空閑
* 2. 空閑則使用
* 4. 不空閑,則等待 池中的單個線程空閑后 使用
*/
ExecutorService service = Executors.newSingleThreadExecutor();
service.execute(new Runnable() {
  @Override
  public void run() {
    System.out.println("線程的名稱:"+Thread.currentThread().getName());
  }
});
service.execute(new Runnable() {
  @Override
  public void run() {
    System.out.println("線程的名稱:"+Thread.currentThread().getName());
  }
});

4. 周期性任務定長線程池

public static void main(String[] args) {
/**
* 周期任務 定長線程池.
* 執(zhí)行流程:
* 1. 判斷線程池是否存在空閑線程
* 2. 存在則使用
* 3. 不存在空閑線程,且線程池未滿的情況下,則創(chuàng)建線程 并放入線程池, 然后使用
* 4. 不存在空閑線程,且線程池已滿的情況下,則等待線程池存在空閑線程
*
* 周期性任務執(zhí)行時:
* 定時執(zhí)行, 當某個時機觸發(fā)時, 自動執(zhí)行某任務 .*/
ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
/**
* 定時執(zhí)行
* 參數1. runnable類型的任務
* 參數2. 時長數字
* 參數3. 時長數字的單位
*/
/*service.schedule(new Runnable() {
  @Override
  public void run() {
    System.out.println("倆人相視一笑~ 嘿嘿嘿");
  }
},5,TimeUnit.SECONDS);
*/
/**
* 周期執(zhí)行
* 參數1. runnable類型的任務
* 參數2. 時長數字(延遲執(zhí)行的時長)
* 參數3. 周期時長(每次執(zhí)行的間隔時間)
* 參數4. 時長數字的單位
*/
  service.scheduleAtFixedRate(new Runnable() {
    @Override
    public void run() {
      System.out.println("倆人相視一笑~ 嘿嘿嘿");
    }
  },5,2,TimeUnit.SECONDS);
}

Runnable 與 Callable

接口定義

//Callable接口
public interface Callable<V> {
  V call() throws Exception;
}
//Runnable接口
public interface Runnable {
  public abstract void run();
}

Callable使用步驟

  1. 編寫類實現(xiàn)Callable接口 , 實現(xiàn)call方法
class XXX implements Callable<T> {
  @Override
  public <T> call() throws Exception {
    return T;
  }
}
  1. 創(chuàng)建FutureTask對象 , 并傳入第一步編寫的Callable類對象
    FutureTask<Integer> future = new FutureTask<>(callable);
  2. 通過Thread,啟動線程
    new Thread(future).start();

Runnable 與 Callable的相同點

  • 都是接口
  • 都可以編寫多線程程序
  • 都采用Thread.start()啟動線程

Runnable 與 Callable的不同點

  • Runnable沒有返回值;Callable可以返回執(zhí)行結果
  • Callable接口的call()允許拋出異常;Runnable的run()不能拋出

Callable獲取返回值

Callalble接口支持返回執(zhí)行結果,需要調用FutureTask.get()得到,此方法會阻塞主進程的繼續(xù)往下執(zhí)行,如果不調用不會阻塞。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 線程基本知識 什么是線程安全性?當多個線程訪問某個類時,這個類始終都能表現(xiàn)出正確的行為,那么可以認為這個類是線程安...
    Cheava閱讀 1,106評論 0 1
  • 一、知識結構分析 多線程之間的關系 pthread是POSIX線程的API NSThread是Cocoa對pthr...
    huoshe2019閱讀 643評論 0 4
  • 先從java開啟一個線程開始說。首先常用的有四種方式:繼承+兩種實現(xiàn)+線程池獲取。其實我們之前大量的demo都是n...
    唯有努力不欺人丶閱讀 193評論 0 3
  • 35. 并行(parallellism )和并發(fā)(concurrency)有什么區(qū)別? 并行:同一時刻有多條指令在...
    CgySHFF閱讀 480評論 0 0
  • 表情是什么,我認為表情就是表現(xiàn)出來的情緒。表情可以傳達很多信息。高興了當然就笑了,難過就哭了。兩者是相互影響密不可...
    Persistenc_6aea閱讀 129,931評論 2 7

友情鏈接更多精彩內容