主頁 > 後端開發 > JavaWeb 基礎知識(二)——執行緒01

JavaWeb 基礎知識(二)——執行緒01

2021-10-17 08:22:58 後端開發

文章目錄

  • JavaWeb 基礎知識(二)多執行緒01
  • 一、認識執行緒
    • 0.執行緒的引入
    • 1.執行緒的概念
    • 2.行程與執行緒
    • 例子
  • 二、Java中的執行緒
  • 1.執行緒的創建
    • (1)run 和 start
    • (2)創建執行緒的幾種方式
    • (3)jconsole 查看執行緒資訊
    • (4)多執行緒的優勢-增加運行速度
  • 2.Thread 的常見構造方法
  • 3.Thread 的幾個常見屬性
    • ID
    • 名稱
    • 狀態
    • 優先級
    • 后臺執行緒
    • 存活
  • 未完待續...


JavaWeb 基礎知識(二)多執行緒01



上節回顧


??我們在介紹本節內容之前,先來簡單復習一下上一節行程的相關內容

在這里插入圖片描述

一、認識執行緒


0.執行緒的引入


??引進行程的目的,就是為了能夠"并發編程"

??雖然多行程已經能夠解決并發的問題了,但是我們認為,還不夠理想,


創建行程、銷毀行程、調度行程開銷有點大了


行程時系統資源分配的基本單位

創建行程,就需要分配資源
銷毀行程,就需要釋放資源


??于是程式員就發明了一個 “執行緒”(Thread)的概念,執行緒在有些系統上也被叫做"輕量級行程".


輕量:
創建執行緒比創建行程更高效
創建執行緒比銷毀執行緒更高效
調度執行緒比調度行程更高效


在這里插入圖片描述

1.執行緒的概念


一個執行緒就是一個 “執行流”. 每個執行緒之間都可以按照順訊執行自己的代碼. 多個執行緒之間 “同時” 執行著多份代碼.


我們站在系統內核的角度,再來看行程和執行緒


一個系統之中可能有很多個PCB(行程控制塊),各個PCB通過鏈表進行連接,如圖代表系統中已有的4個行程 ( pid 分別代表著行程id )在這里插入圖片描述


在Linux系統中,執行緒同樣是使用PCB來描述的


行程1,對應一個PCB,在這個行程1里創建一個執行緒,也是再加了一個PCB
在這里插入圖片描述
??這就是當前我們看到的一個情況,那其實,站在作業系統內核的角度,不分“執行緒”還是“行程”,系統只認PCB


??我們用戶在創建一個行程出來,系統內核方面就會有一個PCB插入到雙向鏈表里面,如果我們在代碼中再去創建一個新的執行緒,也就是再加一個PCB

??像上面的 行程2、行程3、行程4,他們看起來沒有創建其他執行緒,但是行程創建之初,也會有一個PCB產生,我們可以把PCB視作里面的一個執行緒


我們可以得到一個結論:


??當我們創建了一個行程的時候,就是創建了一個PCB 出來,同時這個PCB也可以是當做是目前行程已經包含了一個執行緒了,所以一個行程中至少有一個執行緒,


??同一個行程的執行緒之間,是可以共用一份記憶體空間的,同時其他的行程(PCB)使用的是獨立的記憶體


??也就是說上面的行程中,行程1和執行緒1 共用一份記憶體空間,行程2、行程3、行程4都有自己獨立的記憶體空間,


??這就是我們站在系統內核的角度描述執行緒基本的情況


那我們又茍訓來了,執行緒和代碼有啥關系呢?

可以認為,一個執行緒就是代碼中的一個執行流


執行流:按照一定的順序來執行一組指令

2.行程與執行緒


??行程與執行緒之間本來就是容易搞混淆的,尤其是對于Linux系統來說,行程和執行緒之間又是存在著千絲萬縷的聯系,總之呢,我們得知道 行程和執行緒之間 的區別和聯系


經典面試題


行程和執行緒之間的區別和聯系[面試題]


1、行程是包含執行緒的,一個行程里可以有一個執行緒,同時也可以有多個執行緒,

2、每個行程都有獨立的記憶體空間(虛擬地址空間),同一個行程的多個執行緒之間,共用一個虛擬地址空間,

3、行程是作業系統分配資源的基本單位,執行緒是作業系統調度執行的基本單位

??上節課所介紹的"行程調度",當時咱們是沒有考慮執行緒的,實際上系統是以執行緒(PCB)為單位進行調度執行的.


咱們來畫圖說明:

在這里插入圖片描述
3個行程4個執行緒

??我們先讓CPU處理 第一個PCB塊,執行一段時間之后,把PCB1 釋放,再來執行PCB2,執行一段時間后,再進行釋放,所以系統是根據PCB進行調度執行的.

??以上就是我們所講的 執行緒和行程之間的區別與聯系,上面的三點大家一定要有印象,是后面在面試的時候經常問到的問題,


例子


??剛才我們都一直在干巴巴的講理論,可能是有點抽象了,那我們就再舉一個例子進行說明一下吧(很形象)


主角:滑稽老鐵
道具:封閉的房間與桌上的100只雞

在這里插入圖片描述

現在呢,房間里的桌上有100只雞,如何提高滑稽老鐵吃雞的速度?


那么此時,我們就有兩種方案:


1、多行程


那么多行程是怎么吃呢?


多行程吃雞
在這里插入圖片描述
現在有兩個房間,兩套桌子,把雞平均分成兩份,兩個滑稽老鐵同時再房間各自吃50只雞


??這種分配的方法相比較于之前明顯吃雞的速度要高效好多,

??這就是我們所說的并發編程的效率,能夠提升整體程式的效率


兩個房間、兩套桌子,說明每次再創建行程,都要給這個行程分配一些資源

這兩個房間里的滑稽老鐵,相互之間都看不見彼此,說明行程之間有獨立的地址空間(行程的隔離性)


??這就是我們所說的多行程的吃雞版本!

??當然了,兩個房間、兩套桌子總體來說成本還是有點高的,所以我們為了降低成本,那么我們還可以多執行緒吃雞~


2、多執行緒


多執行緒吃雞怎么吃?我們這樣做~


還是一個房間,只不過多了一個滑稽老鐵來一塊吃雞在這里插入圖片描述
多了一個滑稽老鐵(多了一個吃雞的執行流)


??每個滑稽吃50只雞就行了 ~ 1個人吃50只肯定比1個人吃100只速度更快一些


這里還有一個很重要的問題:


??這兩個滑稽老鐵共用了同一個房間和桌子,一個行程的多個執行緒之間,共用一個虛擬地址空間.同時,這兩個滑稽老鐵是可以看到對方的情況的

只創建了一個滑稽,桌子和房間都沒有新創建,創建這個執行緒的成本比創建行程的成本要更低.


??這就是多執行緒吃雞的一個情況,那么接下來呢?

??我們多執行緒吃雞吃著吃著覺得效率還不夠高,還可以進一步怎么提高效率呢?


進一步提高效率:再多搞幾個滑稽(執行緒)在這里插入圖片描述


??滑稽的數目(執行緒的數目)更多了,每個滑稽的任務就更少了,因此整體的效率就更高了~~

??就是說隨著我們執行緒數目的增多,執行緒去完成同一個任務,我們的速度就會更快

??但是大家注意,這里的速度也不是說執行緒的數目越多越好!!如果執行緒的數目太多了,執行緒之間就會更加頻繁的進行調度,調度的開銷也就無法忽略了!!


就會出現下面的情況
在這里插入圖片描述
我們增加了滑稽(執行緒)的數目,就可能出現有的滑稽搶不上位置(CPU),于是任務的執行速度反而會變慢,這什么意思呢?


??沒有搶著位置的三個老鐵,為了吃雞,要往里面擠,于是已經圍著桌子吃起來的滑稽老鐵們就沒有辦法消停的吃雞了,有的滑稽就可能本來吃的好好的,沒一會被擠出來了,這樣就會出現很多問題~


??所以執行緒也不是越多越好,執行緒的數目越多,就會引發更多的調度開銷,反而可能讓執行任務速度變得更慢~所以這一點呢,大家也要明確.


??還有一種情況,當我們很多滑稽老鐵一起吃雞的時候,可能有打架的行為~~


什么叫打架的情況呢?


還是剛才的飯局
在這里插入圖片描述
兩個滑稽(執行緒)同時看上一個雞大腿(準備修改同一塊記憶體的資料),這個時候就會起沖突.


??這種情況,我們稱為"執行緒不安全",這同樣也是多執行緒編程的重點問題,在后面的章節會著重介紹!!


還有一種情況,如果某個滑稽老鐵不開心,某個滑稽(執行緒)一直搶不到桌子的位置
在這里插入圖片描述
于是這個老鐵一生氣,把桌子給掀了!!


這說明什么呢?


一個行程里面如果某個執行緒拋出了例外,并且沒有合理catch住的話,就可能導致整個行程都例外退出.其他執行緒也就玩完了


??所以一個執行緒不作業,其他的執行緒也全都不作業了,這一點,就對我們的多執行緒程式的安全性提了更高的呃要求

??多執行緒程式的撰寫,其實就提出了一個更高的要求,一定要保證執行緒的穩定


講到這呢,那么我們滑稽的案例就告一段落了~
希望通過這樣的一個例子,讓大家更好的了解行程與執行緒之間的關聯關系


??以上就是我們所介紹的行程與執行緒的關聯與特點,準確的來說是執行緒的一些特點,這些特點我們在以后寫代碼的時候也就會逐步的感受到了~好了,說了那么多,都是理論的知識,理論的知識大家有一個簡單的認識就可以了,重點我們還是要落在代碼上!!


??那么接下來,我們就介紹 使用Java來操作執行緒Thread類(創建執行緒)的相關方法



二、Java中的執行緒


??在Java當中,是使用Thread這個類的物件來表示一個作業系統中的執行緒


PCB是在作業系統內核中,描述執行緒的
而Thread類則是在Java的代碼中 描述執行緒的.


接下來,我們就來寫一下簡單的代碼來創建執行緒出來~


1.執行緒的創建


??首先我們得去創建Thread 的實體出來,但是常見的方式并不是直接new一個物件出來.


??Thread 是Java標準庫中描述的一個關于執行緒的類.


??常見的方式就是自己定義一個類繼承Thread,然后重寫Thread中的 run 方法,run 方法就表示執行緒要執行的具體任務(代碼)


在這里插入圖片描述

start 方法,會在作業系統中真的創建一個執行緒出來(同時在內核中會創建PCB,加入到雙向鏈表當中)

執行一下

在這里插入圖片描述

這個新的執行緒,就會執行 run中所描述的代碼


??看完這個執行緒的創建程序,有的同學不禁會問了,


??我們在 執行代碼的時候 不用 t.start ,直接執行 t.run 行不行?咱們剛才不是把代碼的邏輯定義到run方法里面了嘛,那我們直接呼叫t.run 不是一樣會執行代碼嘛??


執行一下

在這里插入圖片描述


那么run 和 start 方法有什么區別呢?


(1)run 和 start


重點:經典面試題


run 和 start 的區別是非常非常大的,我們來給大家具體演示一下這個情況.


start 方法


當我們運行Java代碼的時候,首先系統會創建一個行程,這個行程里面已經包含了一個執行緒了,這個執行緒執行的代碼默認就是 main 方法 ,main方法呼叫t.start方法,在系統中又會創建一個執行緒(PCB)出來,然后這個PCB執行任務代碼.

在這里插入圖片描述


run 方法


run 方法沒有創建新的PCB,沒有創建新的執行緒.

在這里插入圖片描述

t.run 這里并沒有創建出一個新的執行緒,

而使用t.start 這個方法可以創建出新的執行緒,同時t.start 的兩個執行緒之間是屬于同一行程,屬于并發的關系


例子


如果大家還是沒有懂的話,給大家再舉一個例子:


比如說老王想買一瓶醬油,start 方法就是 老王把兒子小王叫來說,你去樓下超市去買一瓶醬油,run方法就是 老王自己去買一瓶醬油,

這兩種方式的區別,尤其是start,就是在派小王去買醬油的同時,老王自己同時想干嘛就干嘛,這就是并發的效果.而run方法只能老王只能去買醬油了,沒法干其他別的事


這樣的一個區別大家一定要區分請

讓大家看一下程式并發的效果

在這里插入圖片描述


??在上面的代碼中,Mythread 中執行的是一個死回圈,他會一直回圈執行,在主執行緒Main里也會一直執行回圈,那么都是死回圈,這兩個代碼能同時執行嗎?


??按照上面的講解,MyThread 是一個執行流,Main 也是一個執行流,他們屬于并發的關系,所以可以同時執行!


那么運行程式,觀察結果~

在這里插入圖片描述
??“hello main” 和 “hello thread” 進行交替列印,進一步驗證了兩個執行緒并發執行的效果,


??通過剛才這個代碼,我們就可以看到,我們通過執行緒可以讓兩個死回圈按照并發執行的方式,一起來執行,而不是單純的說,一個執行完才去執行另外一個,好了,這是我們通過 start 創建執行緒來這樣做的,如果我們改成 run呢?

在這里插入圖片描述
執行代碼,觀察結果

在這里插入圖片描述


??就會在MyThread 的死回圈中轉不出去,main的回圈無法執行


??這里我們也可以看到 start 和 run之間很本質的區別,run 并沒有創建出新的執行緒,它屬于一個執行緒里面串行執行,而通過start 就可以創建新的執行緒,可以是兩個執行緒以并發的方式同時來執行.


以上就是關于執行緒最基本的代碼~


(2)創建執行緒的幾種方式


??在上面的程式中,我們是通過新建一個類繼承標準庫中的Thread類來創建執行緒的,實際上,執行緒的創建是有很多種方式的,下面我們就來了解一下 Java當中創建執行緒的幾種方式.


1.繼承Thread,重寫run


??我們自己建一個類繼承Thread ,在這個類中重寫run方法.


**加粗樣式**

    class Mythread1 extends Thread{
        @Override
        public void run() {
            // 執行的任務
        }
    }

2.實作Runable介面,重寫 run


Runable 是標準庫提供的一個介面,這個介面主要用于描述"一個任務",里面也是有一個核心的run方法,通過run方法來描述具體要執行的任務代碼是什么…
在這里插入圖片描述


class MyRunable implements Runnable{
    @Override
    public void run() {
        //執行的任務
        while(true){
            System.out.println("hello world");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class Thread1 {

    public static void main(String[] args) {
           Thread t1 = new Thread(new MyRunable());
           t1.start();
    }
}

注意: ??我們的Runable 并不是能夠獨立去使用,還要搭配我們的 Thread 類來進行使用,new MyRunable 的實體作為 Thread 的引數,這就是當前這種方式的寫法.


本質上和剛才繼承Thread重寫Run的效果一樣,都是具體告訴執行緒具體要執行的任務是什么…

只不過MyRunable只是用來描述一個具體的任務是什么,而真正執行緒的主體還是在于我們的Thread類本身.


??同時這種方式,還可以給當前創建的執行緒賦予名字,名字作為Thread 的第二個引數

在這里插入圖片描述


3.繼承Thread,重寫run(匿名內部類)


內部類:在一個類里面定義類

所以匿名內部類就是一個沒有類名的內部類,沒有類名也沒有關系,至少可以創建出一個實體來~

那么我們什么時候需要用到匿名內部類呢?
只需要這個實體,不需要用到其他實體了,
匿名內部類的方式寫起來更加簡潔一些


那么下面我們具體來看具體的代碼應該怎么寫…


   public static void main(String[] args) {
      Thread t = new Thread(){
          @Override
          public void run() {
              // 執行任務代碼
          }
      };
    }

??創建了一個匿名的類,這個類繼承了 Thread,此處new 的實體其實是Thread類的子類的實體


4.實作Runnable 重寫run,使用匿名內部類


??因為都是用的匿名內部類,所以這兩種寫法都很像,但是我們仔細觀察會發現,寫法不太相同.

在這里插入圖片描述

在這里插入圖片描述
我們把兩組代碼拿過來對比一下,可以看出區別來


第一種:我們創建匿名內部類是Thread 的子類,所以 {} 跟在 Thread 的后面

第二種:我們創建的是一個Runnable 這樣的子類,new的 Runnable 子類作為 Thread 的一個引數,相當于創建了一個匿名內部類的實體,把這個實體作為 Thread的引數,


這兩種寫法還是有一定區別的.


??以上的這些創建執行緒的方式,本質上都相同


??只不過區別是,指定執行緒要執行的任務的方式不一樣,此處的區別,其實都是單純的Java語法層面的區別~ 所以這樣的區別并不是很關鍵,這樣的寫法大家只需要多寫兩次去熟練就會了…


好了,寫到這里,可能有同學說了


我們已經了解了創建執行緒的幾種方式了,也知道如何并發執行了,那么有沒有像任務管理器一樣的東西讓我們能夠看到 Java創建的執行緒呢?


(3)jconsole 查看執行緒資訊


??在 JDK 中內置了一個 jconsole 工具,就可以看到執行緒的資訊.

我們先在Java運行一個執行緒

在這里插入圖片描述

點擊運行,看一看jconsole 里面的執行緒資訊


jconsole 在哪里找呢?
先找到我們的jdk檔案,bin目錄下就有 jconsole.exe


打開jconsole 之后出現這樣的界面


在這里插入圖片描述

選擇本地行程Main,然后點擊連接


注意在這里,顯示的行程只是Java相關的行程,非Java的行程顯示不出來

在這里插入圖片描述


??這些執行緒都是當前行程的執行緒,對于一個Java程式來說,啟動的時候不僅啟動了main這樣一個執行緒(main這個執行緒是 main方法對應的執行緒, thread-0 這個就是我們自己創建的新的執行緒),還有很多其他的執行緒,這些執行緒都是JVM在運行的時候內置的一些執行緒…


我們可以通過 這個工具查看每個執行緒的具體情況
在這里插入圖片描述
如果寫的程式,發現程式掛了,就可以通過 jconsole 來查看程式里面每個執行緒的情況,對于分析解決問題就有很大幫助了


??以上就是用 jconsole 來查看 執行緒相關資訊的具體操作,當然了我們還可以根據其他的資訊來查看,我們就暫時不去介紹這么多了~


??好了,我們繼續執行緒的另一塊知識~


(4)多執行緒的優勢-增加運行速度


??之前我們介紹并發編程能夠提高程式的效率,我們呢就通過 Java 的代碼來了解一下 并發編程的效率


這個代碼我們要干什么呢?


首先我們有一個很大的數字,這個數字是10億


首先是串行執行代碼,a、b分別自增10億次

在這里插入圖片描述
我們來看一下執行結果:
在這里插入圖片描述

然后是并發執行,讓a、b分別在兩個執行緒中并發執行自增操作,然后計時.

在這里插入圖片描述

運行查看結果:
在這里插入圖片描述

當前呢,使用并發的方式 確實比 串行的方式時間上 效率提高很多,


串行執行 600—700 ms
并發執行 300—400 ms
速度確實提高了好多

速度提高正好是提高一倍嘛?
不是~(不一定)
主要是因為執行緒調度自身也是有開銷的~

串行執行: 一個執行緒執行了20億次回圈,中間可能調度若干次

并發執行:兩個執行緒各自執行10億次回圈,中間可能調度若干次.


因為系統有調度,所以會對程式的運行時間有影響


2.Thread 的常見構造方法


方法說明
Thread()創建執行緒物件
Thread(Runnable target)使用 Runnable 物件創建執行緒物件
Thread(String name)創建執行緒物件,并命名
Thread(Runnable target, String name)使用 Runnable 物件創建執行緒物件,并命名
【了解】Thread(ThreadGroup group,Runnable target)執行緒可以被用來分組管理,分好的組即為執行緒組,這個目前我們了解即可

具體代碼使用:

Thread t1 = new Thread();
Thread t2 = new Thread(new MyRunnable());
Thread t3 = new Thread("這是我的名字");
Thread t4 = new Thread(new MyRunnable(), "這是我的名字");

3.Thread 的幾個常見屬性


屬性獲取方法
IDgetId()
名稱getName()
狀態getState()
優先級getPriority()
是否是后臺執行緒isDaemon()
是否存活isAlive
是否被中斷isInterrupted

ID


ID 是執行緒的唯一標識,不同執行緒不會重復


名稱


名稱是各種除錯工具會用到


狀態


狀態表示執行緒當前所處的一個情況,和上一節說的"行程的狀態"是類似的效果,存在的意義都是輔助進行執行緒調度


優先級


優先級高的執行緒理論上來說更容易被調度到,和上節課"行程的優先級"是類似的效果


??此處的狀態和優先級 ,和PCB中的狀態優先級并不完全一致,Java執行緒在這個基礎上有做了自己的豐富.


后臺執行緒


關于后臺執行緒,需要記住一點:JVM會在一個行程的所有非后臺執行緒結束后,才會結束運行,

我們在Java中創建的執行緒一般默認都是非后臺執行緒,此時,如果main方法結束了,執行緒還沒結束,JVM不會結束

如果當前執行緒是后臺執行緒,此時如果main方法結束了,執行緒還沒結束,那么JVM行程會直接結束,同時也把這個后臺執行緒給帶走了.


存活


是否存活,即簡單的理解,為 run 方法是否運行結束了
在這里插入圖片描述
存活是什么意思呢》我們來畫一下

在這里插入圖片描述

t中的代碼執行完之后,Java中的執行緒PCB也會同時銷毀嗎?并不會.

Java 中PCB物件在JVM 垃圾回識訓制下才會被銷毀,而作業系統內核的 PCB 在代碼執行完之后就銷毀了

所以我們就可以通過 isAlive() 判斷內核中的PCB是否存在


我們對當前程式中的執行緒查看屬性



class MyRunable implements Runnable{
    @Override
    public void run() {
        //執行的任務
        while (true){
            System.out.println("hello wolrd");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class Thread1 {
    public static void main(String[] args) {
           Thread t1 = new Thread(new MyRunable(),"執行緒01");
           t1.run();
        System.out.println("id: "+t1.getId());
        System.out.println("name: "+t1.getName());
        System.out.println("Priority: " +t1.getPriority());
        System.out.println("State: "+t1.getState());
        System.out.println("isAlive: "+t1.isAlive());
        System.out.println("isDeamon: "+t1.isDaemon());
    }
}

在這里插入圖片描述
在這里插入圖片描述

??好了,今天的執行緒就講到這里,希望大家多多復習~



謝謝欣賞!!



下一篇 JavaWeb基礎知識(三)——執行緒02 敬請期待~



未完待續…

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

標籤:java

上一篇:[java篇]一次性幫你搞懂String,StringBuffer,StringBuilder類

下一篇:記錄C語言學習歷程1---初始C語言1

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