Java的多線程

来源:https://www.cnblogs.com/xiaoran991/archive/2020/02/20/12334171.html
-Advertisement-
Play Games

多線程 1、程式、進程、線程的理解 1.程式(program) 概念:是為了完成特定任務、用某種語言編寫的一組指令的集合。即指一段靜態的代碼塊。 2.線程(process) 概念:程式的一次執行過程,或是正在運行的一個程式。 說明:進程作為資源分配的單位,系統在運行時會為每個進程分配不同的記憶體區域。 ...


多線程

1、程式、進程、線程的理解

1.程式(program)

概念:是為了完成特定任務、用某種語言編寫的一組指令的集合。即指一段靜態的代碼塊。

2.線程(process)

概念:程式的一次執行過程,或是正在運行的一個程式。

說明:進程作為資源分配的單位,系統在運行時會為每個進程分配不同的記憶體區域。

3.線程(thread)

概念:進程可進一步細化為線程,是一個程式內部的一條執行路徑。

說明:線程作為調度和執行的單位,每個線程擁有獨立的運行棧和程式計數器(pc),線程切換的開銷小。

共用同一個進程中的結構:方法區、堆。

 

2、並行和併發

1.單核CPU與多核CPU的理解

1)單核CPU,其實是一種假的多線程,因為在一個時間單元內,也只能執行一個線程的任務。例如:雖然有多車道,但是收費站只有一個工作人員在收費,只有受了費才能通過,那麼CPU就好比收費人員。如果某個人不想交錢,那麼收費人員可以把他“掛起”(晾著他,等他想通了,準備好了錢,再去收費。)但是因為CPU時間單元特別短,因此感覺不出來。

2)如果是多核的話,才能更好的發揮線程的效率。(現在的伺服器都是多核的)

3)一個Java應用程式java.exe,其實至少3個線程,main()主線程,gc()垃圾回收線程,異常處理線程。當然如果發生異常,會影響主線程。

2.並行與併發的理解

1)並行:多個CPU同時執行多個任務。比如:多個人同時做不同的事。

2)併發:一個CPU(採用時間片)同時執行多個任務。比如:秒殺、多個人同做一件事。

 

3、創建多線程的兩種方式

  • 方式一:繼承Thread類的方式:

1)創建一個繼承於Thread類的子類。

2)重寫Thread類的run()-->將此線程執行的操作聲明在run()中。

3)創建Thread類的子類對象

4)通過此對象調用start():1.啟動當前線程;2.調用當前線程的run()。

說明兩個問題:

問題一:我們啟動的線程,必須調用start(),不能調用run()方法啟動線程。

問題二:如果再啟動一個線程,必須重新創建一個Thread子類的對象,調用此對象的start()。

 

  • 方式二:實現Runnab()介面的方式:

1)創建一個是實現了Runnable()介面的類。

2)實現類去實現Runnable中的抽象方法:run()

3)創建類的實現對象。

4)將此對象作為參數傳遞到Thread類的構造器中,創建Thread類的對象。

5)通過Thread類的對象調用start()

 

兩種方式的對比:

1.開發中,優先選擇:實現Runnable介面的方式。

2.原因:1)實現的方式沒類的單繼承性的局限性。

2)實現的方式更適合來處理多個線程共用數據的情況。

聯繫:

public class Thread implements Runnable

相同點:兩種方式都需要重寫run() ,將線程要執行的邏輯聲明在run()中。目前兩種方式,要想啟動線程,都是調用的Thread類中的start()。

 

4、Thread類中的常用方法:

1.start():啟動當前線程;調用當前線程的run()。

2.run():通常需要重寫Thread類中的此方法,將創建的線程要執行的操作聲明在此方法中。

3.currentThread():靜態方法,返回執行當前代碼的線程。

4.getName():獲取當前線程的名字。

5.setName():設置當前線程的名字。

6.yield():釋放當前cpu的執行權。

7.join():線上程a中調用線程b的join(),此時線程a就進入阻塞狀態,直到線程b完全執行完以後,線程a才結束阻塞狀態。

8.stop():已過時。當執行此方法時,強制結束當前線程。

9.sleep(long millitime) :讓當前線程“睡眠”指定的millitime毫秒時間內,當前線程是阻塞狀態。

10.isAlive():判斷當前線程是否存活。

 

線程的優先順序:

  1. MAX_PRIORITY:10

    MIN_PRIORITY:1

    NORM_PRIORITY:5 -->預設優先順序

  2. 如何獲取和設置當前線程的優先順序:

    getPriority():獲取線程的優先順序

    setPriority(int p):設置線程的優先順序

說明:高優先順序的線程要搶占低優先順序的cpu的執行權。但是只是從概率上講,高優先順序的線程高概率的情況下被執行,並不意味著只當高優先順序的線程執行完以後,低優先順序的線程才執行。

線程通信:wait() / notify() / notifyAll():此三種方法定義在Object類中的。

 

補充:線程的分類

一種是守護線程,一種是用戶線程。

 

5、Thread的生命周期

JDK中的Thread.State類中定義了線程的幾種狀態

新建

就緒

運行

阻塞

死亡

 

6、線程的同步機制

在Java中,我們通過同步機制,來解決線程的安全問題。

補充:在實現Runnable介面創建多線程的方式中,我們可以考慮使用this充當同步監視器。

在繼承Thread類創建多線程的方式中,慎用this充當同步監視器,考慮使用當前類充當同步監視器。

 

  • 方法一:同步代碼塊

synchronized(同步監視器){
   //需要被同步的代碼
   
}

說明:1.操作共用數據的代碼,即為需要被同步的代碼。

2.共用數據:多個線程共同操作的變數。

3.同步監視器,俗稱:鎖。任何一個類的對象,都是可以充當鎖。要求:多個線程必須要共用同一把鎖。

 

  • 方法二:同步方法

  1. 同步方法仍然涉及到同步監視器,只是不需要我們顯式的聲明。

  2. 非靜態的同步方法,同步監視器是:this

    靜態的同步方法,同步監視器是:當前類本身

 

  • 方式三:Lock鎖 --- JDK5.0新增

synchronized 與 lock 的異同:

相同:二者都可以解決線程安全問題

不同:synchronized機制在執行完相應的同步代碼以後,自動的釋放同步監視器

Lock需要手動的啟動同步( Lock() ),同時結束同步也需要手動的實現( unlock() )。

 

7、線程通信

例子:使用兩個線程列印1-100,線程1,線程2,交替列印

涉及到三個方法:

wait():一旦執行此方法,當前線程就進入阻塞狀態,並釋放同步監視器。

notify():一旦執行此方法,就會喚醒被wait的一個線程。如果有多個線程被wait,就喚醒優先順序高的。

notifyAll():一旦執行此方法,就會喚醒所有被wait的線程。

 

說明:

1.wait(),notify(),notifyAll()三個方法必須使用在同步代碼塊或同步方法中。

2.wait(),notify(),notifyAll()三個方法的調用者必須是同步代碼塊或同步方法塊中的同步監視器。

3.wait(),notify(),notifyAll()三個方法是定義在java.lang.Object類中的。

 

sleep()和wait()的異同?

1.相同點:一旦執行方法,都可以使得當前的線程進入阻塞狀態。

2.不同點:1) 兩個方法聲明的位置不同:Thread類中聲明sleep(),Object()類中聲明wait()。

2)調用的要求不同:sleep()可以在任何需要的場景下調用,wait()必須使用在同步代碼或同步方中。

3)關於是否釋放同步同步監聽器:如果兩個方法都使用在同步代碼塊或同步方法中 ,sleep()不會釋放 鎖,wait()會釋放鎖。

 

生產者消費者問題:

class Clerk{
   private int productCount = 0;

   public synchronized void produceProduct() {
       if(productCount<20){
           productCount++;
           System.out.println(Thread.currentThread().getName()+":開始生產第"+productCount+"個產品");

           notify();
      }else {
           try {
               wait();
          } catch (InterruptedException e) {
               e.printStackTrace();
          }
      }
  }

   public synchronized void consumeProduct() {
       if(productCount>0){
           System.out.println(Thread.currentThread().getName()+":開始消費第"+productCount+"個產品");
           productCount--;

           notify();
      }else {
           try {
               wait();
          } catch (InterruptedException e) {
               e.printStackTrace();
          }
      }
  }
}

//生產者
class Producer extends Thread{
   private Clerk clerk;

   public Producer(Clerk clerk) {
       this.clerk = clerk;
  }

   @Override
   public void run() {
       System.out.println(getName()+"開始消費產品……");

       while(true){
           try {
               Thread.sleep(2000);
          } catch (InterruptedException e) {
               e.printStackTrace();
          }

           clerk.produceProduct();
      }
  }
}

//消費者
class Consumer extends Thread{
   private Clerk clerk;

   public Consumer(Clerk clerk) {
       this.clerk = clerk;
  }

   @Override
   public void run() {
       System.out.println(getName()+"開始生產產品……");

       while(true){
           try {
               Thread.sleep(1000);
          } catch (InterruptedException e) {
               e.printStackTrace();
          }

           clerk.consumeProduct();
      }
  }
}



public class ProductTest {
   public static void main(String[] args) {
       Clerk clerk = new Clerk();

       Producer p1 = new Producer(clerk);
       p1.setName("生產者1");
       Consumer c1 = new Consumer(clerk);
       c1.setName("消費者1");

       p1.start();
       c1.start();
  }
}

 

 

8、JDK5.0新增線程創建方式

  1. Callable

  2. 線程池

線程池比較有用,以後再來補充。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 點擊添加群聊 今天在整理百度雲盤裡的資源,這幾年累計了不少軟體和教程。 在這特殊的時期里,先給大家分享一波。圖片里的文件夾就是目錄, 加入群聊免費領取 好資源就是要大家一起共用, 你們也不用到處在網上找資源, 或者幫別人轉發到朋友圈才能得到。 只要是我有的,而你也剛好需要,那我願意和你分享。 除了軟 ...
  • 變數提升 聲明的變數會提升到函數或全局作用域頂部 簡單例子 函數提升 函數寫法:函數表達式、函數聲明、Function構造函數(這種不推薦).其中函數表達式不會 函數提升 , 函數聲明 會函數提升。 我們都知道程式在執行時是從上往下執行的,而這裡 在定義之前就調用了為什麼不報錯? 實例一 值為多少? ...
  • 1、首先是設計稿 2、然後使用PxCook進行尺寸標註 3、字體信息去PS里看 4、首頁框架代碼編寫 index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>index</title> <lin ...
  • var eleLink = document.createElement('a'); eleLink.href = "/wordpress/?p=9227"; console.log(eleLink.href); ...
  • 提到new,肯定會和類和實例聯繫起來,如: function Func() { let x = 100; this.num = x + } let f = new Func(); 上面的代碼,我們首先創建了一個函數,如果是用面向對象的說法就是創建了一個Function類的實例,如果直接執行這個函數, ...
  • FOUC(Flash Of Unstyled Content)即瀏覽器樣式閃爍或者叫做無樣式記憶體閃爍(用戶定義樣式表載入之前瀏覽器使用預設樣式顯示文檔,用戶樣式載入渲染之後再從新顯示文檔,造成頁面閃爍。) 解決方法:用link載入css文件,放在head標簽裡面。 ...
  • Vue中的$Bus使用 將Bus單獨抽離成一個文件 Bus.js 創建兩個兄弟組建 C2.vue C1.vue index.vue 註意:這種引入方式,經過webpack打包後可能會出現Bus局部作用域的情況,即引用的是兩個不同的Bus,導致不能正常通信 將Bus註入到Vue的prototype上 ...
  • 我們知道STL中我們常用的 與`multiset map multimap _Rb_tree _Rb_tree`的各個參數的確定。 特別註意在如下代碼的 類用於從 中選出用於排序的key值,這個仿函數必須返回 而不能是 ,否則 會拋出 。由於源碼中邏輯比較複雜,但是可以觀察到內部涉及這方面的地方經常 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...