主頁 > 後端開發 > 【JAVA并發第一篇】Java的行程與執行緒

【JAVA并發第一篇】Java的行程與執行緒

2020-12-08 06:55:37 後端開發

1、行程與執行緒

1.1、行程

行程可以看作是程式的執行程序,一個程式的運行需要CPU時間、記憶體空間、檔案以及I/O等資源,作業系統就是以行程為單位來分配這些資源的,所以說行程是分配資源的基本單位,

(1)、行程是動態的,程式是靜態的

程式是靜態的,它本身作為一種軟體資源可以長期保存在磁盤(常說的硬碟)中,比如QQ,QQ作為一個程式,其本身保存在計算機的磁盤上,此時,它并沒有得到CPU、記憶體、I/O等資源,因此當前的QQ程式只是一個靜態的程式并不能給我們實作視頻、語音等功能,

但當QQ程式開始執行時,作業系統就會將QQ程式從磁盤中裝入記憶體,同時也會在作業系統中創建屬于QQ的行程,這些新創建的QQ行程會得到作業系統分配的CPU、記憶體、I/O等資源,得到這些資源后,創建出來的QQ行程就可以實作視頻和語音的功能,而當我們點擊退出QQ后,這些行程就會立刻消亡,分配得到的資源也會被釋放,

由此可以看出,QQ行程是QQ程式的執行程序,它是動態的,有一定的生命周期,會動態的產生和消亡,行程是資源分配的單位,

(2)、程式與行程并不是一 一對應的關系
雖然行程可以看作是程式的執行程序,但并非一個程式對應一個行程,即二者并不是一 一對應的關系,程式與行程的關系可能有以下幾種:

一個程式產生一個行程:比如Win10的記事本程式(notepad.exe),每打開一個txt文本檔案,就只會啟動一個記事本行程,

一個程式產生多個行程:比如瀏覽器啟動時,一般都會產生多個行程,這些行程相互配合,互相影響,共同實作瀏覽器的功能,

一個程式可以被多個行程共用:比如一個記事本程式在執行時,就只會產生一個行程,但當我們再用記事本程式打開一個檔案時,此時就會再次在作業系統中創建一個新的行程,這個新的行程同樣也會呼叫記事本程式,即在此刻,計算機磁盤中只有一個記事本程式,但是作業系統中卻有兩個記事本行程在共用這個程式,且這兩個行程互不影響,

一個行程又可能要用到多個程式:比如,用C語言寫了一個helloword.c的程式,此時,輸入命令gcc helloword.c,那么作業系統會創建一個行程,它呼叫c編譯程式,對helloword.c檔案進行編譯,這個行程在執行編譯的程序中,除了呼叫c編譯程式和我們撰寫的helloword程式外,還會用到c預處理程式、連接程式、結果輸出程式等,

1.2、執行緒

執行緒從屬于行程,只能在行程的內部活動,多個執行緒共享行程所擁有的的資源,如果把行程看作是完成許多功能的任務的集合,那么執行緒就是集合中的一個任務元素,負責具體的功能,雖然CPU、記憶體、I/O等資源分配給了行程,但實際上真正利用這些資源并在CPU上執行的卻是執行緒,即真正完成程式功能的是執行緒,

因為行程作為這些資源的擁有者,它的負載很重,在行程的創建、切換、洗掉程序中的時間和空間開銷都很大,所以目前主流的作業系統都只將行程作為資源的擁有者,而把CPU調度和運行的屬性賦予了執行緒,

比如打開瀏覽器程式,會產生相應的行程,瀏覽器行程中包含有許多執行緒,如HTTP請求執行緒,I/O執行緒,渲染執行緒,事件回應執行緒等,瀏覽器行程擁有著記憶體和I/O資源等,但當我們在瀏覽器中輸入文字時,真正使用I/O資源接收我們輸入的文字,并在CPU處理文字的卻是瀏覽器行程中的I/O執行緒,即真正完成瀏覽器文字輸入功能的是執行緒,
在這里插入圖片描述

現代很多作業系統支持讓一個行程包含多個執行緒,從而提高程式的并行程度和資源的利用率,

1.3、執行緒與行程的關系

①一個行程可以有多個執行緒,但至少要有一個執行緒,并且一個執行緒只能在一個行程的地址空間內活動,
②資源分配給行程,而一個行程內的所有執行緒共享該行程的所有資源,
③CPU分配給的是執行緒,即真正在CPU上運行的是執行緒,
④行程間通信較為復雜,同一臺計算機的行程通信稱為 IPC(Inter-process communication),
而不同計算機之間的行程通信,則需要通過網路,并遵守共同的協議,例如 HTTP等,
⑤執行緒通信相對簡單,因為它們共享行程內的記憶體,一個例子是多個執行緒可以訪問同一個共享變數,
⑥執行緒更輕量,執行緒背景關系切換成本一般上要比行程背景關系切換低,

2、Java中的行程與執行緒

2.1、JVM行程

我們知道Java語言是需要運行在JVM上的,實際上,JVM也是一個軟體程式,這就意味著它執行起來也會在作業系統中創建行程,即JVM行程,通常又叫JVM實體,而我們所寫的main方法,實際上就是JVM行程中主執行緒的所在,

從作業系統的角度來看,我們常說的Java程式,應該包括JVM和我們撰寫的Java代碼,

當我們寫完Java代碼,并編譯成class檔案后,使用Java命令執行main方法;或者直接在IDE啟動main方法時,JVM程式就會執行,作業系統會將其從磁盤中裝入記憶體,并創建一個JVM行程,隨后啟動主執行緒,主執行緒會去呼叫某個類的 main 方法,因此這個主執行緒就是我們寫的main方法所在,

實際上,JVM本身就是一個多執行緒應用,即使我們在代碼中并沒有手動的創建執行緒,JVM行程也并不是只有一個主執行緒,而是也會有其他執行緒,這些執行緒完成著JVM的功能,如GC執行緒負責回收JVM使用程序中的垃圾物件,JVM行程啟動完成后,必然會有的執行緒如下:

執行緒 作用
main 主執行緒,執行我們指定的啟動類的main方法
Reference Handler 處理參考的執行緒
Finalizer 呼叫物件的finalize方法的執行緒
Signal Dispatcher 分發處理發送給JVM信號的執行緒
Attach Listener 負責接收外部的命令的執行緒

至此,我們知道了,啟動一個Java程式,本質上就是啟動JVM程式,并在作業系統中創建一個JVM行程,這個JVM行程會由作業系統分配許多資源,如記憶體、I/O等,JVM行程中包含有許多執行緒,這些執行緒共享JVM行程分配到的資源,同時這些執行緒也是CPU核心上執行的物體,它們完成著JVM所具有的功能,

那么如果我們啟動兩個Java程式,會生成多少個JVM行程呢?

我們撰寫兩個Java程式,其有代碼如下:

processTest01程式

public class processTest01 {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("我是測驗01");
        byte[] a = new byte[1024*1024*50]; //在堆中占50MB
        processTest02 test02 = new processTest02();
        Thread.sleep(1000*60*30);   //休眠三十分鐘
    }
}

processTest02程式

public class processTest02 {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("我是測驗02");
        byte[] a = new byte[1024*1024*900]; //在堆中占900MB
        Thread.sleep(1000*60*30);   //休眠三十分鐘
    }
}

我們將編譯這兩個程式,并分別用Java命令啟動它們,看看兩個Java程式會在作業系統中創建了多少個行程,
在這里插入圖片描述
打開JDK自帶的jvisualvm.exe,這是JDK提供的查看Java行程和執行緒相關資訊的工具程式,在自己電腦上的JDK目錄下(Win10):Java\jdk1.8.0_131\bin,如圖所示:
在這里插入圖片描述
可以繼續使用jvisualvm,查看行程中執行緒的相關情況:

pid(行程號)為2146的行程:
在這里插入圖片描述
pid(行程號)為4196的行程:
在這里插入圖片描述
可以看出,啟動多少個Java程式,就會創建多少個JVM行程,也稱之為JVM實體,而每一個JVM實體都是獨立的,它們互不影響,這也是前面所說的一個程式可以被多個行程共用的情況,

一個JVM行程就是一個JVM的實體,JVM的實體在執行Java程式的程序中會把它管理的記憶體劃分為不同區域,稱之為運行時資料區,如下所示:

在這里插入圖片描述

2.2、Java的執行緒

我們知道,執行緒從屬于行程,是CPU調度執行的單位,各個執行緒共享行程內的資源,目前主流的作業系統都支持了執行緒,在實作了執行緒的作業系統中,一個行程中必然有至少一個作業系統的執行緒,這種屬于作業系統的執行緒被稱為內核執行緒(kernel-Level Thread,KLT),

而各個應用程式實作多執行緒的方式主要有三種:

①內核執行緒1:1實作
內核執行緒即作業系統本身的執行緒,1:1意味著程式中的執行緒與作業系統中的內核執行緒是直接對應的,這種執行緒的創建是由作業系統來完成的,同時也是由作業系統來負責調度的,這種內核執行緒的切換需要硬體支持,切換所需的時間也較長,但其優點是一個執行緒阻塞了,其他執行緒也可以執行,則行程就能繼續作業,但一般來說,程式中的執行緒不會直接使用內核執行緒,而是使用它提供的高級介面,稱之為輕量級行程(Light Weight Process,LWP),雖然名稱變了,但其本質上還是作業系統的內核執行緒,每個輕量級行程,都由一個內核執行緒支持,所以他們都可以獨立調度,由作業系統的調度器(Scheduler)負責調度,總的來說就是,程式中的執行緒是作業系統的內核執行緒,

在這里插入圖片描述

可以看出,使用內核執行緒1:1實作的程式可以同時在多個CPU核心上跑,也就是說,程式執行產生的一個行程中的多個執行緒在同一時刻可能會在不同的CPU核心上運行,這對于一個程式來說,大大加快了運行效率,

②用戶執行緒1:N實作

用戶執行緒指的是由用戶程式自主實作,不需要作業系統來實作的執行緒,一個執行緒不是內核執行緒,就可以認為是用戶執行緒,用戶執行緒雖然不需要作業系統來實作,但在實作了執行緒的作業系統中,一個行程中必然要有一個內核執行緒來支持運行,1:N中的1就是一個內核執行緒的意思,而N指的是用戶程式自主實作的多用戶執行緒,作業系統無法得知這些用戶執行緒的存在,因為這些用戶執行緒都是在用戶程式內部建立、切換和銷毀的,由于用戶執行緒不需要作業系統的幫助,所以對于用戶執行緒的操作可以非常快,消耗低,且不需要硬體的支持,同時,用戶執行緒的的數量不受作業系統的限制,在沒有實作多執行緒的作業系統中也可以實作多執行緒程式,但由于用戶執行緒需要映射為內核執行緒才能執行,所以如果一個執行緒阻塞,那么所有的執行緒都將阻塞,行程也無法繼續作業,執行緒的調度也是由用戶程式自主實作,總的來說,用戶執行緒就是用戶的程式自主實作的執行緒,多個用戶執行緒對應著一個作業系統的內核執行緒
在這里插入圖片描述
可以看出,用戶執行緒1:N實作的程式,一個行程中的多用戶執行緒在同一時刻只能在一個CPU核心上運行,因為只有一個內核執行緒支持著這個行程,從作業系統角度來看,這就是一個單執行緒的行程,當然,如果一個實作了用戶執行緒的程式執行產生了多個行程,那么實際上這個程式也可能在多個CPU核心上跑,目前很少有程式實作這種用戶執行緒了,

③混合N:M實作
混合實作即用戶執行緒和內核執行緒一起使用的實作方式,在這種混合實作下,即存在用戶執行緒,又存在輕量級行程(內核執行緒),用戶執行緒還是由用戶程式自主實作,這樣用戶執行緒的創建、切換、銷毀依然快速且消耗低,而一個用戶執行緒的集合(包含一個或多個用戶執行緒)又與一個內核執行緒映射,多個用戶執行緒的集合,就是N:M實作中的N,而M自然指的是多個內核執行緒,這樣的情況下,也可以繼續使用作業系統的調度功能,而且由于一個內核執行緒支持著一個用戶執行緒的集合,所以一個用戶執行緒阻塞,并不會阻塞其他用戶執行緒,行程也能繼續工佐,總的來說,混合實作就是一個用戶執行緒的集合對應著一個內核執行緒,一個行程中會存在多個用戶執行緒集合,則會有多個內核執行緒來支持運行,

在這里插入圖片描述
可以看出,由于用戶執行緒集合映射到了一個內核執行緒上,而一個行程又有多個用戶執行緒集合,所以使用混合實作多執行緒的程式,行程中也可能存在多個用戶執行緒在不同CPU核心上執行的情況

Java執行緒的實作

介紹完程式實作多執行緒的三種方式,那么Java是如何實作多執行緒的呢?

首先,Java虛擬機規范并未規定要如何實作多執行緒,所以Java的執行緒都是由虛擬機來具體實作,不同的虛擬機實作執行緒的方式可能都不相同,不過,在JDK1.2之前,早期的虛擬機都采用的是用戶執行緒1:N的實作方式,而在JDK1.3之后,大部分的虛擬機都采用了內核執行緒1:1實作的方式,包括我們最常用的HostSpot虛擬機,

這就意味著,我們在平常的開發中,不論是JVM程式自己創建的執行緒,還是我們手動編碼創建的執行緒,實際上都是直接1:1映射到了作業系統的內核執行緒, 這一內核執行緒由作業系統來創建,且虛擬機不會去干涉執行緒調度,Java的執行緒何時交給CPU核心去執行,交給哪個CPU核心,執行緒有多少CPU核心的執行時間,執行緒何時凍結、喚醒等等,都交給作業系統去完成,也都是作業系統全權決定(不過Java虛擬機也可以設定執行緒優先級來給作業系統的執行緒調度提供建議),

3、多執行緒與并行、并發

兩個或兩個以上的執行緒在同一時刻發生就稱為并行,如兩個執行緒在同一時刻在兩個不同的CPU核心上執行,則可以說這兩個執行緒是并行執行,

兩個或兩個以上的執行緒在同一時間段內發生則稱為并發,比如兩個執行緒在一個極短的時間段上分別在同一個CPU核心上執行,則可以說這兩個執行緒是并發執行,

并行與并發的關鍵就在于是否為同一時刻執行,并行是在同一時刻執行,而并發則是在極短的時間內執行,

在一個CPU核心中,執行緒實際是并發執行的,作業系統中有一個組件叫做任務調度器,將cpu核心的時間片(windows下時間片最小約為 15 毫秒)分給不同的程式使用,只是由于cpu核心在執行緒間(時間片很短)的切換非常快,給人的感覺是同時運行的,但實際上一個CPU核心同一時刻只能支持一個執行緒運行,即如果是在單個CPU核心的作業系統中,Java程式(包含JVM)本身雖然是多執行緒的,但實際上,同一時刻只能有一個Java執行緒在執行,

在這里插入圖片描述
但目前的計算機已經很少有單個核心的CPU了,目前即使是個人使用的計算機都是多個核心的CPU了,每個核心都可以獨立調度運行執行緒,這就意味著執行緒之間可以并行執行,

在這里插入圖片描述
可以看出,在多核心的CPU下,執行緒之間是可以并行執行的,但即使是擁有多個CPU核心的計算機,CPU核心的數量始終是有限的,而一個作業系統中的執行緒數遠遠多于CPU核心數,所以執行緒之間大部分情況下是屬于并發狀態的,即執行緒之間是在極短時間下交替在CPU核心上執行的,

需要注意的是,在單個CPU核心下,多執行緒其實是沒有太大意義的,因為始終只能有一個執行緒在CPU核心上執行,而執行緒間的切換是需要耗費時間和資源的,但多核CPU可以同時執行執行緒,如果在多核CPU中還是使用單執行緒,無疑是對CPU的巨大浪費,并發的最主要的目的就是最大限度利用CPU資源,

但并發并不是執行緒特有的,行程之間也可以并發,有些語言實作并發就是使用行程來進行并發,如PHP,不過Java的并發依然是依賴于多執行緒,即多執行緒是Java實作并發的一種方式,

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/231289.html

標籤:Java

上一篇:由Java 15廢棄偏向鎖,談談Java Synchronized 的鎖機制

下一篇:阿里終面:怎么用 UDP 實作 TCP?

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more