主頁 > 後端開發 > Java的執行緒

Java的執行緒

2023-05-15 07:29:29 後端開發

介紹執行緒

執行緒是系統調度的最小單元,一個行程可以包含多個執行緒,執行緒是負責執行二進制指令的,

每個執行緒有自己的程式計數器、堆疊(Stack)、暫存器(Register)、本地存盤(Thread Local)等,但是會和行程內其他執行緒共享檔案描述符、虛擬地址空間等,

對于任何一個行程來講,即便我們沒有主動去創建執行緒,行程也是默認有一個主執行緒的,


守護執行緒(Daemon Thread)

有的時候應用中需要一個長期駐留的服務程式,但是不希望這個服務程式影回應用退出,那么我們就可以將這個服務程式設定為守護執行緒,如果 Java 虛擬機發現只有守護執行緒存在時,將結束行程,

在 Java 中將執行緒設定為守護執行緒,具體的實作代碼如下所示:

public static void main(String[] args) {
    Thread daemonThread = new Thread();
    // 必須在執行緒啟動之前設定
    daemonThread.setDaemon(true);
    daemonThread.start();
}

通用的執行緒生命周期

在作業系統層面,執行緒有生命周期,

對于有生命周期的事物,要學好它,只要能搞懂生命周期中各個節點的狀態轉換機制就可以了,

通用的執行緒生命周期基本上可以用下圖這個 “五態模型” 來描述,這五態分別是:初始狀態、可運行狀態、運行狀態、休眠狀態和終止狀態,

1651248522968-14a3c935-b45e-4ab7-bb1c-f7de1e93bf1d.png

這“五態模型”的詳細情況如下所示,


初始狀態

初始狀態,指的是執行緒已經被創建,但是還不允許被 CPU 調度,

初始狀態屬于編程語言特有的,這里所謂的被創建,僅僅是在編程語言層面被創建,而在作業系統層面,真正的執行緒還沒有被創建,

在 Java 中,初始狀態相當于是創建了 Thread 類的物件,但是還沒有呼叫 Thread#start() 方法,


可運行狀態

可運行狀態,指的是執行緒可以被作業系統調度,但是執行緒還沒有開始執行,

在可運行狀態下,真正的作業系統執行緒已經被創建,多個執行緒處于可運行狀態時,作業系統會根據調度演算法選擇一個執行緒運行,

在 Java 中,可運行狀態相當于是呼叫了 Thread#start() 方法,但是執行緒還沒有被分配 CPU 執行,


運行狀態

當有空閑的 CPU 時,作業系統會將空閑的 CPU 分配給一個處于可運行狀態的執行緒,被分配到 CPU 的執行緒的狀態就從可運行狀態轉換成了運行狀態,

在 Java 中,運行狀態相當于是呼叫了 Thread#start() 方法,并且執行緒被分配 CPU 執行,


休眠狀態

如果運行狀態的執行緒呼叫了一個阻塞的 API(例如以阻塞的方式讀取檔案)或者等待某個事件(例如條件變數),那么執行緒的狀態就會從運行狀態轉換到休眠狀態,同時釋放 CPU 的使用權,休眠狀態的執行緒永遠沒有機會獲得 CPU 的使用權,

當等待的資源或條件滿足后,執行緒就會從休眠狀態轉換到可運行狀態,并等待 CPU 調度,


終止狀態

執行緒執行完畢或者出現例外,執行緒就會進入終止狀態,即執行緒的生命周期終止,


這五種狀態在不同編程語言里會有簡化合并,例如:

  • C 語言的 POSIX Threads 規范,就把初始狀態和可運行狀態合并了;
  • Java 程式設計語言把可運行狀態和運行狀態合并了,這兩個狀態在作業系統調度層面有用,而 Java 虛擬機層面不關心這兩個狀態,因為 Java 虛擬機把執行緒調度交給作業系統處理了,

除了簡化合并,這五種狀態也有可能被細化,比如,Java 語言里就細化了休眠狀態(這個下面我們會詳細講解),

Java 的執行緒生命周期

不同的程式設計語言對于作業系統執行緒進行了不同的封裝,下面我們學習一下 Java 的執行緒生命周期,

Java 程式設計語言中,執行緒共有六種狀態,分別是:

  1. NEW(初始狀態)
  2. RUNNABLE(可運行 / 運行狀態)
  3. BLOCKED(阻塞狀態)
  4. WAITING(無時限等待)
  5. TIMED_WAITING(有時限等待)
  6. TERMINATED(終止狀態)

NEW(初始狀態)、TERMINATED(終止狀態)和通用的執行緒生命周期中的語意相同,

在作業系統層面,Java 執行緒中的 BLOCKED、WAITING、TIMED_WAITING 是一種狀態,即通用的執行緒生命周期中的休眠狀態,也就是說只要 Java 執行緒處于這三種狀態之一,那么這個執行緒就永遠沒有機會獲得 CPU 的使用權,

所以 Java 中的執行緒生命周期可以簡化為下圖:

1651248522988-a3b8cd59-986b-49ee-8743-c262c7a1c180.png


其中,可以將 BLOCKED、WAITING、TIMED_WAITING 理解為導致執行緒處于休眠狀態的三種原因,

  • 那具體是哪些情形會導致執行緒從 RUNNABLE 狀態轉換到這三種狀態呢?
  • 而這三種狀態又是何時轉換回 RUNNABLE 的呢?
  • 以及 NEW、TERMINATED 和 RUNNABLE 狀態是如何轉換的?

下面我們詳細講解,

Java 的執行緒狀態切換

從 NEW 到 RUNNABLE 狀態

剛創建 Thread 類的物件時,執行緒處于 NEW 狀態,

NEW 狀態的執行緒,不會被作業系統調度,因此不會執行,Java 執行緒要執行,就必須轉換到 RUNNABLE 狀態,

從 NEW 狀態轉換到 RUNNABLE 狀態只要呼叫執行緒物件的 start() 方法就可以了,具體的實作代碼如下所示:

public static void main(String[] args) {
    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("hello");
        }
    });
    thread.start();
}

從 RUNNABLE 到 TERMINATED 狀態

執行緒執行完 Thrad#run() 方法后,會自動從 RUNNABLE 狀態轉換到 TERMINATED 狀態,

如果執行 run() 方法的時候例外了拋出,也會導致執行緒終止,進入 TERMINATED 狀態 ,

1. RUNNABLE 與 BLOCKED 的狀態轉換

只有一種場景會觸發 RUNNABLE 與 BLOCKED 的狀態轉換,就是執行緒等待 synchronized 的隱式鎖,

  • 當使用 synchronized 申請加鎖失敗時,該執行緒的狀態就會從 RUNNABLE 轉換到 BLOCKED 狀態,
  • 當等待的執行緒獲得鎖時,該執行緒的狀態就會從 BLOCKED 狀態轉換到 RUNNABLE 狀態,

如果你熟悉作業系統執行緒的生命周期的話,可能會有個疑問:執行緒呼叫阻塞式 API 時,是否會轉換到 BLOCKED 狀態呢?在作業系統層面,執行緒是會轉換到休眠狀態的,但是在 Java 虛擬機層面,Java 執行緒的狀態不會發生變化,也就是說 Java 執行緒的狀態會依然保持 RUNNABLE 狀態,

Java 虛擬機層面并不關心作業系統調度相關的狀態,因為在 Java 虛擬機看來,等待 CPU 的使用權(作業系統層面此時處于可執行狀態)與等待 I/O(作業系統層面此時處于休眠狀態)沒有區別,都是在等待某個資源,所以都歸入了 RUNNABLE 狀態,

而我們說的 Java 執行緒在呼叫阻塞式 API 時,執行緒會阻塞,指的是作業系統執行緒的狀態,并不是 Java 執行緒的狀態,

2. RUNNABLE 與 WAITING 的狀態轉換

總體來說,有三種場景會觸發 RUNNABLE 與 WAITING 的狀態轉換,


第一種場景,獲得 synchronized 隱式鎖的執行緒,呼叫無引數的 Object#wait() 方法,

這里應該呼叫的是鎖物件的 wait() 方法,具體的實作代碼如下所示:

public void method() throws InterruptedException {
    synchronized (this) {
        this.wait();
    }
}
  • 當呼叫 wait() 方法時,呼叫方法的執行緒的狀態從 RUNNABLE 狀態轉換到 WAITING 狀態
  • 當呼叫 notify() 方法時,被喚醒的執行緒的狀態從 WAITING 狀態轉換到 RUNNABLE 狀態

第二種場景,呼叫無引數的 Thread#join() 方法,

join() 是一種執行緒同步方法,例如有一個執行緒物件 thread A:

  • 當呼叫 A.join() 方法時,執行這條陳述句的執行緒會等待 thread A 執行完,而等待中的這個執行緒,其狀態會從 RUNNABLE 轉換到 WAITING,
  • 當執行緒 thread A 執行完,原來等待它的執行緒又會從 WAITING 狀態轉換到 RUNNABLE,

Thread#join() 方法的實作基于 Object#wait(),


第三種場景,呼叫 LockSupport#park() 方法,

LockSupport 類,也許你有點陌生,其實 Java 并發包中鎖的實作都用到了 LockSupport#park() / unpark(),

  • 當呼叫 LockSupport.park() 方法時,呼叫方法的執行緒的狀態從 RUNNABLE 轉換到 WAITING,
  • 當呼叫 LockSupport.unpark(Thread thread) 方法時,被喚醒的執行緒的狀態從 WAITING 狀態轉換到 RUNNABLE 狀態

總結來說:Object#wait() 和 LockSupport#park() 方法使執行緒的狀態轉換到 WAITING,

3. RUNNABLE 與 TIMED_WAITING 的狀態轉換

總體來說,有五種場景會觸發 RUNNABLE 與 TIMED_WAITING 的狀態轉換:

  1. 獲得 synchronized 隱式鎖的執行緒,呼叫帶超時引數的 Object#wait(long timeout) 方法;
  2. 呼叫帶超時引數的 Thread#join(long millis) 方法;(底層呼叫 Object#wait(long timeout) )
  3. 呼叫帶超時引數的 LockSupport.parkNanos(Object blocker, long deadline) 方法;
  4. 呼叫帶超時引數的 LockSupport.parkUntil(long deadline) 方法,
  5. 呼叫帶超時引數的 Thread.sleep(long millis) 方法;

這里你會發現:

  • TIMED_WAITING 和 WAITING 狀態的區別,僅僅是觸發條件多了超時引數,
  • 與 RUNNABLE 與 WAITING 的狀態轉換 相比,多了一個 Thread.sleep() 場景,

Java 執行緒 API 的使用

執行緒的創建

創建執行緒的幾種方式:

  1. 繼承 Thread 類,重寫 run() 方法,
  2. 實作 Runnable 介面,實作其中的 run() 方法,將該實作類的物件作為引數傳遞到 Thread 類的構造器中,創建 Thread 類的物件,
  3. 實作 Callable 介面,實作其中的 call() 方法,將該實作類的物件作為引數傳遞到 FutureTask 類的構造器中,創建FutureTask 類的物件,將 FutureTask 類的物件作為引數傳遞到 Thread 類的構造器中,創建 Thread 類的物件,Callable 它解決了 Runnable 無法回傳結果的困擾,

「實作 Runnable 介面」VS「繼承 Thread 類」

  • 通過實作(implements)的方式沒有類的單繼承性的局限性
  • 實作的方式更適合處理多個執行緒有共享資料的情況

「實作 Callable 介面」VS「實作 Runnable 介面」

  • call() 可以有回傳值
  • call() 可以拋出例外被外面的操作捕獲,獲取例外的資訊
  • 「實作 Callable 介面」支持泛型

// 自定義執行緒物件
class MyThread extends Thread {
    public void run() {
        // 執行緒需要執行的代碼
        ......
    }
}

// 創建執行緒物件
MyThread myThread = new MyThread();
// 實作Runnable介面
class Runner implements Runnable {
    @Override
    public void run() {
        // 執行緒需要執行的代碼
        ......
    }
}

// 創建執行緒物件
Thread thread = new Thread(new Runner());
public static void main(String[] args) throws ExecutionException, InterruptedException {
    MyTask task = new MyTask();
    // FutureTask 用于接收運算結果
    FutureTask futureTask = new FutureTask<>(task);
    Thread thread = new Thread(futureTask);

    thread.start();
	// FutureTask 可用于執行緒間同步 (當前執行緒等待其他執行緒執行完成之后,當前執行緒才繼續執行)
    // get() 回傳值即為 FutureTask 構造器引數 Callable 實作類實作的 call() 的回傳值
    System.out.println(futureTask.get());
}

public class MyTask implements Callable {
    @Override
    public String call() {
        // 若不需要回傳值,可 return null;
        return "ok";
    }
}

執行緒的執行

創建好 Thread 類的物件后,通過呼叫 Thread#start() 方法創建執行緒執行任務,

執行緒執行要呼叫 start() 而不是直接呼叫 run(),直接呼叫 run() 方法只會在當前執行緒上同步執行 run() 方法的內容,而不會啟動新執行緒,呼叫 start() 方法的作用:

  1. 啟動一個新的執行緒
  2. 新的執行緒呼叫 run() 方法

執行緒的停止

有時候我們需要強制中斷 run() 方法的執行,例如 run() 方法訪問一個很慢的網路,我們等不下去了,想終止怎么辦呢?Java 的 Thread 類里面倒是有個 stop() 方法,不過已經標記為 @Deprecated,所以不建議使用了,正確的方式是呼叫 interrupt() 方法,Thread#interrupt() 配合合適的代碼,即可優雅的實作執行緒的終止,

stop() 和 interrupt() 方法的區別,

  • stop() 方法會真的殺死執行緒,不給執行緒喘息的機會,如果執行緒持有 ReentrantLock 鎖,被 stop() 的執行緒并不會自動呼叫 ReentrantLock 的 unlock() 去釋放鎖,那其他執行緒就再也沒機會獲得 ReentrantLock 鎖,這實在是太危險了,所以該方法就不建議使用了,類似的方法還有 suspend() 和 resume() 方法,這兩個方法同樣也都不建議使用了,
  • interrupt() 方法僅僅是通知執行緒,執行緒有機會執行一些后續操作,執行緒也可以無視這個通知,被 interrupt 的執行緒,是怎么收到通知的呢?一種是例外,另一種是主動檢測,

例外

當執行緒 A 處于 WAITING、TIMED_WAITING 狀態時,如果其他的執行緒呼叫執行緒 A 的 interrupt() 方法,會使執行緒 A 回傳到 RUNNABLE 狀態,同時執行緒 A 的代碼會觸發 InterruptedException 例外,

上面我們提到轉換到 WAITING、TIMED_WAITING 狀態的觸發條件,都是呼叫了類似 wait()、join()、sleep() 這樣的方法,我們看這些方法的簽名,發現都會 throws InterruptedException 這個例外,這個例外的觸發條件就是:其他的執行緒呼叫了該執行緒的 interrupt() 方法,

當執行緒 A 處于 RUNNABLE 狀態時:

  • 當執行緒 A 處于 RUNNABLE 狀態,并且阻塞在 java.nio.channels.InterruptibleChannel 上時,如果其他的執行緒呼叫執行緒 A 的 interrupt() 方法,執行緒 A 會觸發 java.nio.channels.ClosedByInterruptException 這個例外;
  • 當執行緒 A 處于 RUNNABLE 狀態,并且阻塞在 java.nio.channels.Selector 上時,如果其他的執行緒呼叫執行緒 A 的 interrupt() 方法,執行緒 A 的 java.nio.channels.Selector 會立即回傳,

上面這兩種情況屬于被中斷的執行緒通過例外的方式獲得了通知,


主動檢測

還有一種是主動檢測,如果執行緒處于 RUNNABLE 狀態,并且沒有阻塞在某個 I/O 操作上,例如中斷計算圓周率的執行緒 A,這時就得依賴執行緒 A 主動檢測中斷狀態了,如果其他的執行緒呼叫執行緒 A 的 interrupt() 方法,那么執行緒 A 可以通過 isInterrupted() 方法,檢測是不是自己被中斷了,

參考資料

第17講 | 一個執行緒兩次呼叫start()方法會出現什么情況?-極客時間 (geekbang.org)

09 | Java執行緒(上):Java執行緒的生命周期 (geekbang.org)

06 | 執行緒池基礎:如何用執行緒池設計出更“優美”的代碼? (geekbang.org)

11 | 執行緒:如何讓復雜的專案并行執行?-極客時間 (geekbang.org)

本文來自博客園,作者:真正的飛魚,轉載請注明原文鏈接:https://www.cnblogs.com/feiyu2/p/thread.html

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

標籤:其他

上一篇:如何優雅得關閉協程呢

下一篇:返回列表

標籤雲
其他(159011) Python(38129) JavaScript(25421) Java(18034) C(15226) 區塊鏈(8265) C#(7972) AI(7469) 爪哇(7425) MySQL(7184) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5871) 数组(5741) R(5409) Linux(5340) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4572) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2433) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1972) 功能(1967) Web開發(1951) HtmlCss(1936) python-3.x(1918) C++(1915) 弹簧靴(1913) xml(1889) PostgreSQL(1876) .NETCore(1860) 谷歌表格(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
最新发布
  • Java的執行緒

    介紹執行緒 執行緒是系統調度的最小單元,一個行程可以包含多個執行緒,執行緒是負責執行二進制指令的。 每個執行緒有自己的程式計數器、堆疊(Stack)、暫存器(Register)、本地存盤(Thread Local)等,但是會和行程內其他執行緒共享檔案描述符、虛擬地址空間等。 對于任何一個行程來講,即便我們沒有主動 ......

    uj5u.com 2023-05-15 07:29:29 more
  • 如何優雅得關閉協程呢

    1.簡介 本文將介紹首先為什么需要主動關閉goroutine,并介紹如何在Go語言中關閉goroutine的常見套路,包括傳遞終止信號和協程內部捕捉終止信號。之后,文章列舉了需要主動關閉協程運行的常見場景,如啟動一個協程執行一個不斷重復的任務。希望通過本文的介紹,讀者能夠掌握如何在適當的時候關閉go ......

    uj5u.com 2023-05-15 07:24:22 more
  • 【pandas基礎】--資料整理

    pandas進行資料整理的意義在于,它是資料分析、資料科學和機器學習的前置步驟。 通過資料整理可以提前了解資料的概要,缺失值、重復值等情況,為后續的分析和建模提供更為可靠的資料基礎。 本篇主要介紹利用pandas進行資料整理的各種方法。 1. 資料概要 獲取資料概要資訊可以幫助我們了解資料的基本情況 ......

    uj5u.com 2023-05-15 07:24:17 more
  • 數字分頻器設計(偶數分頻、奇數分頻、小數分頻、半整數分頻、狀態

    偶數分頻:無論是通過D觸發器還是計數器實作,這類分頻都是最容易得到的,并且占空比容易控制在50%。對于D觸發器實作偶數分頻來說,分頻數只能得2^n,其余分頻數只能由計數器法等其他方法實作。除此以外,隨著分頻的數目不斷增大,通過D觸發器實作觸發器數目會增多,在電路設計的程序中應當考慮面積因素。對于計數... ......

    uj5u.com 2023-05-15 07:24:09 more
  • 數字分頻器設計(偶數分頻、奇數分頻、小數分頻、半整數分頻、狀態

    偶數分頻:無論是通過D觸發器還是計數器實作,這類分頻都是最容易得到的,并且占空比容易控制在50%。對于D觸發器實作偶數分頻來說,分頻數只能得2^n,其余分頻數只能由計數器法等其他方法實作。除此以外,隨著分頻的數目不斷增大,通過D觸發器實作觸發器數目會增多,在電路設計的程序中應當考慮面積因素。對于計數... ......

    uj5u.com 2023-05-15 07:22:13 more
  • R語言資料繪圖學習(0x01)-安裝ggplot2與嘗試

    0x01 安裝與R基礎 一直聽說資料分析里R語言是比較‘正統’,況且久聞ggplot2這些R語言的資料分析庫大名,想到今后資料分析和整理的需要,這里開一個簡單的系列學習一些R語言和ggplot2的繪圖基礎。本人學習的書籍是Winston Chang大佬的《R Graphics Cookbook》,且 ......

    uj5u.com 2023-05-13 07:41:55 more
  • python高級技術(行程二)

    一 行程物件及其他方法 '''一臺計算機上面運行著很多行程,那么計算機是如何區分并管理這些行程服務端的呢?計算機會給每一個運行的行程分配一個PID號如何查看 windows電腦 進入cmd輸入tasklist即可查看 tasklist|findstr PID查看具體的行程 linux電腦 進入終端之 ......

    uj5u.com 2023-05-13 07:36:35 more
  • 使用 IDEA 時突然斷電導致 git 本地分支損壞的解決方案

    使用IDEA提交專案的時候突然斷電,重啟后專案 git 損壞,所有檔案變成了 untracked,IDEA 界面上表示為所有檔案名變成綠色,并且無法 pull (也可能是無法 push) 提示 Git Pull Failed From http://***************** * branc ......

    uj5u.com 2023-05-13 07:24:33 more
  • Spring AOP 分享

    初級篇 AOP是什么? Aspect-oriented Programming (AOP) 即面向切面編程。簡單來說,AOP 是一種編程范式,允許我們模塊化地定義橫跨多個物件的行為。AOP 可以幫助我們將應用程式的關注點分離,使得代碼更加清晰、易于維護和擴展。 大白話:在方法執行前后運行指定代碼,比 ......

    uj5u.com 2023-05-13 07:22:03 more
  • 閱讀論文的方法和技巧(快速且有效)

    如何從一個小白快速開始入手看論文,然后看論文,發論文。請仔細看下面的講解。歡迎大家一起交流和補充。 閱讀論文的方法和技巧 一.閱讀論文五個重要步驟(通常用時30-60分鐘) 1.第一遍是快速瀏覽論文的摘要、結論、框架圖,有助于把握核心,對論文的內容形成整體感知。(5-10分鐘) 當然,這一遍建議在網 ......

    uj5u.com 2023-05-12 10:48:00 more