主頁 > 後端開發 > 我看誰還不懂多執行緒之間的通信+基礎入門+實戰教程+詳細介紹+附原始碼

我看誰還不懂多執行緒之間的通信+基礎入門+實戰教程+詳細介紹+附原始碼

2022-11-06 06:25:35 後端開發

一、多執行緒之間的通信(Java版本)

1、多執行緒概念介紹

多執行緒概念

  • 在我們的程式層面來說,多執行緒通常是在每個行程中執行的,相應的附和我們常說的執行緒與行程之間的關系,執行緒與行程的關系:執行緒可以說是行程的兒子,一個行程可以有多個執行緒,但是對于執行緒來說,只屬于一個行程,再說說行程,每個行程的有一個主執行緒作為入口,也有自己的唯一標識PID,它的PID也就是這個主執行緒的執行緒ID

  • 對于我們的計算機硬體來說,執行緒是行程中的一部分,也是行程的的實際運作單位,它也是作業系統中的最小運算調度單位,多執行緒可以提高CPU的處理速度,當然除了單核CPU,因為單核心CPU同一時間只能處理一個執行緒,在多執行緒環境下,對于單核CP來說,并不能提高回應速度,而且還會因為頻繁切換執行緒背景關系導致性能降低,多核心CPU具有同時并行執行執行緒的能力,因此我們需要注意使用環境,執行緒數超出核心數時也會引起執行緒切換,并且作業系統對我們執行緒切換是隨機的,

2、執行緒之間如何通信

引入

  • 對于我們Java語言來說,多執行緒編程也是它的特性之一,我們需要利用多執行緒操作同一共享資源,從而實作一些特殊任務,上面說了,多執行緒在進行切換時CPU隨機調度的,假如我們直接運行多個執行緒操作共享資源的話,勢必會引起一些不可控錯誤因素,
  • 接下來,我們就需要讓這些不可控變為可控 !這個時候就引出了本文的重點執行緒通信,執行緒通信就是為了解決多執行緒對同一共享變數的爭奪

Java 執行緒通信的方式

  • 共享記憶體機制
    • 比如說Java的volatile關鍵字就是基于記憶體屏障解決變數的可見性,從而實作其他執行緒訪問共享變數都是必須從主存中獲取(對應其他執行緒對變數的更新也得及時的重繪到主存),
    • synchronized 關鍵字基于物件鎖這種方式實作執行緒互斥,可以通知對方有其他的執行緒正在執行這部分代碼,
  • 訊息傳遞模式
    • wait() 和 notify()/notifyAll() 等待通知方式實作執行緒的阻塞就緒狀態之間的轉換,
    • park、unpark
    • join() 阻塞【底層也是依賴wait實作】,
    • interrupt()打斷阻塞狀態,
    • 管道輸入/輸出,

3、執行緒通信方法詳細介紹

主要介紹wait/notify,也有ReentrantLock的Condition條件變數的await/signal,LockSupport的park/unpark方法,也能實作執行緒之間的通信,主要是阻塞/喚醒通信模式,

首先說明這種方法一般都是作用于呼叫方法的所在執行緒,比如在主執行緒執行wait方法,就是將主執行緒阻塞了,

wait/notify機制

  • wait()、notify方法在Java中是Object提供給我們的,又因為所有的類都默認隱式繼承了Object類,進而我們的每一個物件都具有wait和notify,
    • wait方法含義:一個執行緒一旦呼叫了任意物件obj.wait()方法,它就釋放了所持有的監視器物件(obj)上的鎖,并轉為非運行狀態(阻塞),
    • notify方法含義:一個執行緒若執行obj.notify方法,則隨機喚醒obj物件上監視器(作業系統也稱為管程)monitor的阻塞佇列waitset中一個執行緒,
    • wait和notify方法的使用同時必須配合synchronized關鍵字使用,同時也需要成對出現,就是說wait和notify必須得在同步代碼塊內部使用,大致原因就是需要保證同時只有一個執行緒可以去執行wait,使該執行緒阻塞,

await/signal

  • 要想使用await/signal首先是需要借用Condition條件變數,要想獲取Condition條件變數,就必須通過ReentrantLock鎖獲取,
  • ReentrantLock和Synchronized類似,都是可重入鎖,并且大多都是當做重量級鎖使用,
    • 區別:ReentrantLock是API層面實作的,我們可以根據自己隨意呼叫定制,但是Synchronized是JVM底層實作,我們無需關心他上鎖解鎖的流程,
  • await/signal使用時需要配合ReentrantLock鎖物件的lock和unlock方法加鎖解鎖,就像wait/notify在synchronized在同步代碼塊中使用一樣,他們都需要保證當前執行緒是唯一執行這段邏輯的執行緒,防止出現多執行緒造成的執行緒安全問題,

park/unpark

二、執行緒通信程序中需要注意的問題

1、喚醒丟失

如果一個執行緒先于被通知執行緒呼叫wait()前呼叫了notify(),等待的執行緒將錯過這個信號,

  • 喚醒丟失主要是在我們使用wait 和 notify的程序中的時序問題,比如說我們執行緒二在執行某個物件notify的時候,執行緒一還沒有執行該物件的wait方法,那么這次的喚醒就會丟失,我們就不能讓執行緒二得notify方法起作用,自然而然執行緒一就不會被喚醒,
  • 舉個例子吧,這就好比我們平常在宿舍每天都會有叫醒服務,但是這次 因為一些原因(通宵···)我一整晚都沒有睡覺,而且當第二天早上的叫醒服務來的 時候也是醒著的,那么叫醒服務就會以為你已經醒來了,就會視而不見,沒想到吧,叫醒服務剛走我就躺下來睡著了,所以我錯過了這次叫醒服務,就能好好的睡覺了,這看起來沒有什么大問題,但是你仔細想想若是每個睡著的人都需要被叫醒服務才能醒過來,外加上只有一次叫醒服務的機會,那么你就可以沉睡萬年了,開心不,
  • 哈哈哈···
  • 這在程式中也是一樣 的,如果錯過notify那么就會一直wait,
    • 所以我們必須預防這種問題,比如說每隔一段時間去喚醒,也就是隔兩分鐘就去叫醒睡著的人,但是這種缺點就是太累了,對于程式來說是消耗性能和記憶體,實作也簡單就是寫入while回圈體中,不停地嘗試即可,
    • 我們也可以使用一個標志位完美的實作,初始化設定flag=FALSE表示還沒wait,在wait之前將設定flag=TRUE,在notify之后設定flag=FALSE,每次notify喚醒之前都判斷flag=true是否已經wait,在wait中判斷flag=false是否已經notify,

核心代碼演示

  • 首先使用執行緒池創建執行緒一使自己進入阻塞態,然后再呼叫LOCK1的notify方法喚醒執行緒一
	    // 執行緒一使用LOCK1物件呼叫wait方法阻塞自己
        executor.execute(new ThreadTest("執行緒一",LOCK1,LOCK2));

        synchronized (LOCK1) {
            System.out.println("main執行notify方法讓執行緒一醒過來");
            LOCK1.notify();
        }
  • 但是他很有可能醒不來,因為主執行緒呼叫LOCK1物件的notify方法,可能主執行緒已經執行完了,上面執行緒還沒創建完成,也就是沒有進入wait狀態,就醒不來了,

  • 解決方式:使用信號量標志進行判斷是否已經進入wait

            synchronized (LOCK1) {
                while (true) {
                    if (FLAG.getFlag()) {
                        System.out.println("main馬上執行notify方法讓執行緒一醒過來" + "flag = " + FLAG.getFlag());
                        LOCK1.notify();
                        // 將標志位變為FALSE
                        FLAG.setFlag(Constants.WaitOrNoWait.NO_WAIT.getFlag());
                        System.out.println("main執行notify方法完畢" + "flag = " + FLAG.getFlag());
                        break;
                    }
                }
            }
    

2、假喚醒

由于莫名其妙的原因,執行緒有可能在沒有呼叫過notify()和notifyAll()的情況下醒來,

  • 其實在上面的代碼中已經解決了假喚醒的問題,因為我們只需要不斷去嘗試獲取標志位資訊即可,

3、多執行緒喚醒

  • 多個執行緒執行時,防止notifyAll全部喚醒之后就結束運行,我們的需求是只能喚醒一個執行緒,當其他執行緒被喚醒之后需要重新判斷標志位是否為FALSE,也就是需要判斷是否有其他執行緒執行了喚醒操作,因為一次只能叫醒一個人,需要排隊,他們就可以繼續自旋判斷,
		synchronized (waitName) {
            while (!flag.getFlag()) {
                try {
                    // 將標志位設定為TRUE
                    flag.setFlag(Constants.WaitOrNoWait.WAIT.getFlag());
                    System.out.println("name;"+name+" 我睡著了進入阻塞狀態" + "flag = " + flag.getFlag());
                    waitName.wait();
                    System.out.println("name;"+name+" 我醒來了" + "flag = " + flag.getFlag());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
  • 大家如果使用的是new Thread()方式創建執行緒的話,要想保證安全的話還可以給該標志位加上volatile關鍵字,可以時刻保證該標志位的可見性,
  • 我這里使用的標志位是使用傳遞參考的方式,使用同一個物件,將標志位定義為該物件中的屬性,然后再結合列舉類進行設定標志位的值,因為我使用執行緒池創建物件,并且自定義執行緒類,這里是無法設定全域變數,傳遞給執行緒類,包裝類也不行哦,(感興趣可以親自試一下)
  • 大體代碼結構如下所示:
	private final static Object LOCK1 = new Object();
    private final static Object LOCK2 = new Object();
    private final  static Constants.WaitStatus FLAG = new Constants.WaitStatus(false);
    public static void main(String[] args) throws InterruptedException {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 5, 1, TimeUnit.DAYS, new ArrayBlockingQueue<>(4), new ThreadPoolExecutor.AbortPolicy());
        executor.execute(new ThreadTest("執行緒一",LOCK1,LOCK2, FLAG));
        // ···喚醒
    }

class ThreadTest implements Runnable { //阻塞··· }

完整代碼可以看這[Gitee倉庫完整代碼][https://gitee.com/malongfeistudy/javabase/tree/master/Java多執行緒_Study/src/main/java/com/mlf/thread/demo_wait_notify]

三、執行緒通信實戰

前置知識:執行緒池的使用方法

  • 首先復習一下創建執行緒的幾種方式和其的優缺點:

    • 通過new Thread()
    • 繼承Thread():和new Thread沒啥區別,就是耦合度低了
      • 定義執行緒類繼承Thread類并且重寫run方法即可,
      • 優點是簡潔方便
      • 缺點是占用了該類的單繼承位置,無法繼承其他父類
    • 實作Runnable介面
    • 實作Callable介面
      • 和實作Runnable介面類似
      • 優點:
        • 實作介面,不占用繼承的位置;
        • 耦合度降低,并且可定化程度提高,各個模塊之間的呼叫關系更加清晰
      • 缺點:
        • 實作起來稍微麻煩
  • 使用執行緒池的步驟

    • 執行緒池初始化方式:
      • 使用Executor初始化執行緒池
        • 優點:方便快捷,適用于自己測驗時使用
        • 缺點:在實際開發中無法判斷細節
      • new ThreadPoolExecutor()構造器創建(本文使用方式)
        • 優點:可以清晰地定制出適合自己的執行緒池,不會造成資源浪費
        • 缺點:麻煩
  • 在主執行緒自定義執行緒池使用實體,這里需要根據實際情況定義鎖物件,因為我們需要使用這些鎖物件控制多執行緒之間的運行順序以及執行緒之間的通信,在Java中每個物件都會在初始化的時候擁有一個監視器,我們需要利用好他進行并發編程,這種創建執行緒池的方法也是阿里巴巴推薦的方式,想想以阿里的體量多年總結出來的總沒有錯,大家還是提前約束自己的編碼習慣等,安裝一個阿里代碼規范的插件對自己的程式員道路是比較nice的,

    /**
     * 每個使用對應唯一的物件作為監視器物件鎖,
     */
    public static final Object A_O = new Object();
    public static final Object B_O = new Object(); 
        /** 引數:
         * int corePoolSize,                     核心執行緒數
         * int maximumPoolSize,                  最大執行緒數
         * long keepAliveTime,                   救急存活時間
         * TimeUnit unit,                        單時間位
         * BlockingQueue<Runnable> workQueue,    阻塞佇列
         * RejectedExecutionHandler handler      拒絕策略
         **/
        // 使用阿里巴巴推薦的創建執行緒池的方式
        // 通過ThreadPoolExecutor建構式自定義引數創建
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                3,
                5,
                1,
                TimeUnit.DAYS,
                new ArrayBlockingQueue<>(2),
                new ThreadPoolExecutor.AbortPolicy());
  • 接下來需要自定義執行緒類,我們可以自定義執行緒類,并且在該執行緒類中定義自己需要的共享資源(鎖物件,屬性等),在run方法中寫盡自己的執行緒運行邏輯即可,
class ThreadDiy implements Runnable {

    private final String name;

    /**
     * 阻塞鎖物件  等待標記
     **/
    private final Object waitFor;

    /**
     * 執行鎖物件  下一個標記
     **/
    private final Object next;

    public AlternateThread(String name, Object waitFor, Object next) {
    }

    @Override
    public void run() {
        // 執行緒的代碼邏輯···
    }

}

1、控制兩個執行緒之間的執行順序

題目:現在有兩個執行緒,不論執行緒的啟動順序,我需要指定執行緒一先執行,然后執行緒二再執行,

  • 初始化兩個物件鎖作為執行緒監視器,

        private final static Object ONE_LOCK = new Object();
        private final static Object TWO_LOCK = new Object();
    
  • 接下來初始化執行緒池,上面有具體的介紹,在這就不多說了

  • 使用執行緒池去執行我們的兩個執行緒,在這里我們需要分析的是

        // 使用執行緒池創建執行緒
        executor.execute(new DiyThread(1, ONE_LOCK, TWO_LOCK));
        executor.execute(new DiyThread(2, TWO_LOCK, ONE_LOCK));

        synchronized (ONE_LOCK) {
            ONE_LOCK.notify();
        }

創建執行緒類

  • 我們使用繼承Runnable的方式去創建執行緒物件,需要在這個類中實作每個執行緒執行的邏輯,我們根據題目可以得出,我們要控制每個執行緒的執行順序,怎么辦?那么就要實作所有執行緒之間的通信,通信方式采用wait-notify的方式即可,我們使用wait-notify的時候必須結合synchronized,那么就需要控制兩個物件鎖,因為我們不光是控制自己,還有另一個執行緒,

  • 我們再分析一下題意,首先需要指定先后執行的順序,那么就需要實作兩個執行緒之間的通信,其次呢,我們得控制兩個執行緒,那么就需要兩個監視器去監視這兩個執行緒,

  • 我們定義這兩個監視器物件為own和other,然后再新增一個屬性threadId來標識自己,

        private final int threadId;
        private final Object own;
        private final Object other;
    
  • 接下來就是撰寫Run方法了

  • 每個執行緒首先需要阻塞自己,等待喚醒,然后喚醒之后,再去喚醒另外一個執行緒,這樣就實作了自定義順序,至于先喚醒哪個執行緒,交給我們的主執行緒去完成,

  • 這里需要注意的是,如果我們只是單純地執行了多個執行緒物件,但是主執行緒沒有主動去喚醒其中一個,這樣就會形成類似于死鎖的回圈等待,你需要我喚醒,我需要你喚醒,這個時候需要主執行緒去插手喚醒其中的任意一個執行緒,

    • 第一步阻塞自己own

              synchronized (own) {
                  try {
                      own.wait();
                      System.out.println(num);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
      
    • 第二步喚醒other

              synchronized (other) {
                  other.notify();
              }
      

2、多執行緒交替列印輸出

題目需求:現在需要使用三個執行緒輪流列印輸出,說白了也就是多執行緒輪流執行罷了,和問題一控制兩個執行緒列印順序沒什么區別

  • 還是老步驟,首先需要定義執行緒類,我們需要控制當前執行緒和下一個執行緒即可,我們這里需要兩個物件,一個是阻塞鎖物件用來阻塞當前執行緒,另一個是喚醒鎖物件,用來喚醒下一個物件,
    /**
     * 阻塞鎖物件  等待標記
     **/
    private final Object waitFor;
    /**
     * 喚醒鎖物件  下一個標記
     **/
    private final Object next;
  • run方法的邏輯和上面的基本一樣, 一個執行緒一旦呼叫了任意物件的wait()方法,它就釋放了所持有的監視器物件上的鎖,并轉為非運行狀態,

  • 每個執行緒首先會呼叫 waitFor物件的 wait()方法,隨后該執行緒進入阻塞狀態,等待其他執行緒執行自己參考的該 waitFor物件的 notify()方法即可,

    		while (true) {
                synchronized (waitFor) {
                    try {
                        waitFor.wait();
                        System.out.println(name + " 開始執行");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                synchronized (next) {
                    next.notify();
                }
            }
    
  • 主執行緒需要初始化執行緒池、執行三個執行緒,并且最后需要打破僵局,因為此時每個執行緒都是阻塞狀態,他們沒法阻塞/喚醒回圈下去,

            synchronized (A_O) {
                A_O.notify();
            }
    
  • 模擬執行流程

/**
 * 模擬執行流程
 * 列印名(name)    等待標記(waitFor)   下一個標記(next)
 *      1                 A                  B
 *      2                 B                  C
 *      3                 C                  A
 * 
 * 像不像Spring的回圈依賴:確實很像,Spring中的回圈依賴就是 BeanA 依賴 BeanB,BeanB 依賴 BeanA;
 * 他們實體化程序中都需要先屬性注入對方的實體,倘若剛開始的時候都沒有實體化,初始化就會死等,類似于死鎖,
 **/

3、多執行緒順序列印同一個自增變數

使用多執行緒輪流列印 01234····

  • 思路:使用自增原子變數AtomicInteger和多執行緒配合列印,

具體代碼請移步到Gitee倉庫:[順序列印自增變數][https://gitee.com/malongfeistudy/javabase/blob/master/Java多執行緒_Study/src/main/java/com/mlf/thread/print/AddNumberPrint2.java]

條件變數Condition的使用

  • Condition是一個 LOCK 實體出來的,他們獲取的都是一個 LOCK 的鎖,而如果要呼叫 object的 wait和notify 方法,首先要獲取對應的object的鎖,如果要呼叫Condition 的await、signal方法,必須先獲取Lock鎖(Lock.lock),
  • 多執行緒的初衷就是操作共享資源,然后我們需要保證共享資源同一時刻只能被一個執行緒所修改,那么就需要一把鎖來控制這些執行緒之間互斥條件,這里使用一個ReentrantLock鎖作為我們的Lock物件,通過同一個 Lock鎖 獲取的每個Condition 就可以作為每個執行緒自己的阻塞條件和喚醒條件,

如有問題,請留言評論,

作者:小白且菜鳥出處:https://www.cnblogs.com/malongfeistudy/

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

標籤:其他

上一篇:【python】都2022年不會還有人不會在電腦桌面上養寵物吧~

下一篇:20行代碼簡單python爬蟲,爬蟲實體

標籤雲
其他(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