国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

第六章volatile詳解

這篇具有很好參考價值的文章主要介紹了第六章volatile詳解。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

volatile修飾的變量有2大特點

可以保證

  • 可見性
  • 有序性

為什么能實現(xiàn)這些功能,其底層原理就是內(nèi)存屏障

volatile的內(nèi)存語義

volatile關(guān)鍵字可以保證共享變量可見性,相較于普通的共享變量,使用volatile關(guān)鍵字可以保證共享變量的可見性

  • 當線程讀取的是volatile關(guān)鍵字時,JMM會把該線程對應的工作內(nèi)存設置為無效,線程直接從主內(nèi)存中讀取該值到工作內(nèi)存中
    • yield和sleep會導致線程讓出CPU,當線程再次調(diào)度回CPU,有可能會重新讀主存(JVM規(guī)范明確表示,yield和sleep方法不一定會強行刷新工作內(nèi)存,讀取主存,但是volatile會強行刷新內(nèi)存)
  • 當線程寫的是volatile關(guān)鍵字變量,將當前修改后的變量值(工作內(nèi)存中)立即刷新到主內(nèi)存,且其他正在讀此變量的線程會等待(不是阻塞),直到寫回主內(nèi)存操作完成,保證讀的一定是刷新后的主內(nèi)存值

一句話,volatile修飾的變量在某個工作內(nèi)存修改后立刻會刷新會主內(nèi)存,并把其他工作內(nèi)存的該變量設置為無效。

內(nèi)存屏障

回憶volatile的作用

  • 可見性

    • 立即刷新回主內(nèi)存+失效處理。
  • 有序性

    • 禁止指令重排:存在數(shù)據(jù)依賴關(guān)系的禁止重排。

是什么

  • 內(nèi)存屏障(也稱內(nèi)存柵欄,內(nèi)存柵障,屏障指令等,是一類同步屏障指令,是CPU或編譯器在對內(nèi)存隨機訪問的操作中的一個同步點,使得此點之前的所有讀寫操作都執(zhí)行后才可以開始執(zhí)行此點之后的操作),避免代碼重排序。

  • 內(nèi)存屏障其實就是一種JVM指令,Java內(nèi)存模型的重排規(guī)則會要求Java編譯器在生成JVM指令時插入特定的內(nèi)存屏障指令 ,通過這些內(nèi)存屏障指令,volatile實現(xiàn)了Java內(nèi)存模型中的可見性和有序性,但volatile無法保證原子性 。

    • 內(nèi)存屏障之前的所有寫操作都要回寫到主內(nèi)存,

    • 內(nèi)存屏障之后的所有讀操作都能獲得內(nèi)存屏障之前的所有寫操作的最新結(jié)果(實現(xiàn)了可見性)。

    • 一句話:對一個 volatile 域的寫, happens-before 于任意后續(xù)對這個 volatile 域的讀,也叫寫后讀。

內(nèi)存屏障分類

  • 上一章講解過happens-before先行發(fā)生原則,類似接口規(guī)范,落地?
  • 落地靠什么?你憑什么可以保證?你管用嗎?

粗分兩種

寫屏障(Store Memory Barrier) :告訴處理器在寫屏障之前將所有存儲在緩存(store bufferes) 中的數(shù)據(jù)同步到主內(nèi)存。也就是說當看到Store屏障指令, 就必須把該指令之前所有寫入指令執(zhí)行完畢才能繼續(xù)往下執(zhí)行。

讀屏障(Load Memory Barrier) :處理器在讀屏障之后的讀操作, 都在讀屏障之后執(zhí)行。也就是說在Load屏障指令之后就能夠保證后面的讀取數(shù)據(jù)指令一定能夠讀取到最新的數(shù)據(jù)。

細分四種

第六章volatile詳解

什么叫保證有序性

  • 禁止指令重排
    • 通過內(nèi)存屏障禁止重排
  1. 重排序有可能影響程序的執(zhí)行和實現(xiàn), 因此, 我們有時候希望告訴JVM你別“自作聰明”給我重排序, 我這里不需要排序, 聽主人的。

  2. 對于編譯器的重排序, JMM會根據(jù)重排序的規(guī)則, 禁止特定類型的編譯器重排序。

  3. 對于處理器的重排序, Java編譯器在生成指令序列的適當位置, 插入內(nèi)存屏障指令, 來禁止特定類型的處理器排序。

volatile 的底層實現(xiàn)原理是內(nèi)存屏障,Memory Barrier(Memory Fence)

  • 對 volatile 變量的寫指令后會加入寫屏障
    • 寫屏障會確保指令重排序時,不會將寫屏障之前的代碼排在寫屏障之后
  • 對 volatile 變量的讀指令前會加入讀屏障
    • 讀屏障會確保指令重排序時,不會將讀屏障之后的代碼排在讀屏障之前

寫屏障(Store Memory Barrier) :告訴處理器在寫屏障之前將所有存儲在緩存(store bufferes) 中的數(shù)據(jù)同步到主內(nèi)存。也就是說當看到Store屏障指令, 就必須把該指令之前所有寫入指令執(zhí)行完畢才能繼續(xù)往下執(zhí)行。

讀屏障(Load Memory Barrier) :處理器在讀屏障之后的讀操作, 都在讀屏障之后執(zhí)行。也就是說在Load屏障指令之后就能夠保證后面的讀取數(shù)據(jù)指令一定能夠讀取到最新的數(shù)據(jù)。

happens-before之volatile變量規(guī)則

對一個 volatile 域的寫, happens-before 于任意后續(xù)對這個 volatile 域的讀,也叫寫后讀。

第六章volatile詳解

這里暫時先有個印象著就行

  • 當?shù)谝粋€操作為volatile讀時,不論第二個操作是什么,都不能重排序。這個操作保證了volatile讀之后的操作不會被重排到volatile讀之前。

  • 當?shù)诙€操作為volatile寫時,不論第一個操作是什么,都不能重排序。這個操作保證了volatile寫之前的操作不會被重排到volatile寫之后

  • 當?shù)谝粋€操作為volatile寫時,第二個操作為volatile讀時,不能重排。

JMM就將內(nèi)存屏障插入策略分為4種規(guī)則

讀屏障

  • 在每個volatile讀操作的后面插入一個LoadLoad屏障
  • 在每個volatile讀操作的后面插入一個LoadStore屏障

寫屏障

  • 在每個volatile寫操作的前面插入一個StoreStore屏障

  • 在每個volatile寫操作的后面插入一個StoreLoad屏障

第六章volatile詳解

volatile特性

如何保證可見性

volatile 的底層實現(xiàn)原理是內(nèi)存屏障,Memory Barrier(Memory Fence)

  • 對 volatile 變量的寫指令后會加入寫屏障
    • 保證在該屏障之前的,對共享變量的改動,都同步到主存當中
  • 對 volatile 變量的讀指令前會加入讀屏障
    • 保證在該屏障之后,對共享變量的讀取,加載的是主存中最新數(shù)據(jù)

寫屏障(Store Memory Barrier) :告訴處理器在寫屏障之前將所有存儲在緩存(store bufferes) 中的數(shù)據(jù)同步到主內(nèi)存。也就是說當看到Store屏障指令, 就必須把該指令之前所有寫入指令執(zhí)行完畢才能繼續(xù)往下執(zhí)行。

讀屏障(Load Memory Barrier) :處理器在讀屏障之后的讀操作, 都在讀屏障之后執(zhí)行。也就是說在Load屏障指令之后就能夠保證后面的讀取數(shù)據(jù)指令一定能夠讀取到最新的數(shù)據(jù)。

說明

  • 保證不同線程對某個變量完成操作后結(jié)果及時可見,即該共享變量一旦改變所有線程立即可見。

例子

public class VolatileTest1 {
//    static boolean flag = true;//不加volatile,沒有可見性
    static volatile boolean flag = true;//加volatile,有可見性
    public static void main(String[] args) throws InterruptedException {
        new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"\t come in");
            while (flag){//默認flag是true,如果未被修改就一直循環(huán),下面那句話也打不出來

            }
            System.out.println(Thread.currentThread().getName()+"\t flag被修改為false,退出.....");

        },"t1").start();
        //暫停幾秒
        TimeUnit.SECONDS.sleep(2);
        flag=false;
        System.out.println("main線程修改完成");
    }
}
//沒有volatile時
//t1   come in
//main線程修改完成
//--------程序一直在跑(在循環(huán)里)

//有volatile時
//t1   come in
//main線程修改完成
//t1   flag被修改為false,退出.....

上述代碼原理解釋

  • 線程t1中為何看不到被主線程main修改為false的flag的值?

問題可能:

  • 主線程修改了flag之后沒有將其刷新到主內(nèi)存,所以t1線程看不到。

  • 主線程將flag刷新到了主內(nèi)存,但是t1一直讀取的是自己工作內(nèi)存中flag的值,沒有去主內(nèi)存中更新獲取flag最新的值。

我們的訴求:

  • 線程中修改了工作內(nèi)存中的副本之后,立即將其刷新到主內(nèi)存;
  • 工作內(nèi)存中每次讀取共享變量時,都去主內(nèi)存中重新讀取,然后拷貝到工作內(nèi)存。

解決:

  • 使用volatile修飾共享變量,就可以達到上面的效果,被volatile修改的變量有以下特點:

    • 線程中讀取的時候,每次讀取都會去主內(nèi)存中讀取共享變量最新的值 ,然后將其復制到工作內(nèi)存
    • 線程中修改了工作內(nèi)存中變量的副本,修改之后會立即刷新到主內(nèi)存

volatile變量的讀寫過程

Java內(nèi)存模型定義了8種每個線程工作內(nèi)存與物理主內(nèi)存之間的原子操作

  • read(讀取)→load(加載)→use(使用)→assign(賦值)→store(存儲)→write(寫入)→lock(鎖定)→unlock(解鎖)
  • read: 作用于主內(nèi)存,將變量的值從主內(nèi)存?zhèn)鬏數(shù)焦ぷ鲀?nèi)存,主內(nèi)存到工作內(nèi)存
  • load: 作用于工作內(nèi)存,將read從主內(nèi)存?zhèn)鬏數(shù)淖兞恐捣湃牍ぷ鲀?nèi)存變量副本中,即數(shù)據(jù)加載
  • use: 作用于工作內(nèi)存,將工作內(nèi)存變量副本的值傳遞給執(zhí)行引擎,每當JVM遇到需要該變量的字節(jié)碼指令時會執(zhí)行該操作
  • assign: 作用于工作內(nèi)存,將從執(zhí)行引擎接收到的值賦值給工作內(nèi)存變量,每當JVM遇到一個給變量賦值字節(jié)碼指令時會執(zhí)行該操作
  • store: 作用于工作內(nèi)存,將賦值完畢的工作變量的值寫回給主內(nèi)存
  • write: 作用于主內(nèi)存,將store傳輸過來的變量值賦值給主內(nèi)存中的變量

由于上述6條只能保證單條指令的原子性,針對多條指令的組合性原子保證,沒有大面積加鎖,所以,JVM提供了另外兩個原子指令:

  • lock: 作用于主內(nèi)存,將一個變量標記為一個線程獨占的狀態(tài),只是寫時候加鎖,就只是鎖了寫變量的過程。
  • unlock: 作用于主內(nèi)存,把一個處于鎖定狀態(tài)的變量釋放,然后才能被其他線程占用

其中最核心的操作是在于我們的write操作,當我們從工作內(nèi)存寫到主內(nèi)存的時候,會進行l(wèi)ock加鎖操作,加鎖后會清空其他線程工作內(nèi)存變量的值,如果其他線程要使用該變量前必須重寫從主內(nèi)存加載值,當write完畢后,進行unlock進行解鎖 ,這樣就保證了可見性

  • 這里的鎖只是鎖了些變量的過程,也就是只有寫完之后,其他線程才能到主內(nèi)存去讀數(shù)據(jù)

為何沒有原子性

  • volatile變量的復合操作不具有原子性,比如number++

例子

  • synchronizedvolatile代碼演示
class MyNumber{
    //volatile int num=0;
    int num=0;
    public synchronized void add(){
        num++;
    }
}
public class VolatileNoAtomicDemo {
    public static void main(String[] args) {
        MyNumber myNumber = new MyNumber();
        for (int i = 0; i <10; i++) {
            new Thread(()->{
                for (int j = 0; j < 100; j++) {
                    myNumber.add();
                }
            }).start();
        }
        //暫停幾秒鐘線程
        try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
        System.out.println(Thread.currentThread().getName() + "\t" + myNumber.num);

    }

}
//-------------volatile情況下
//main  941
//-----------synchronized請款下
//main  1000

讀取賦值一個普通變量的情況

當線程1對主內(nèi)存對象發(fā)起read操作到write操作第一套流程的時間里,線程2隨時都有可能對這個主內(nèi)存對象發(fā)起第二套操作

  • 當線程1開始了volatile的讀寫流程的時候,線程2可以在其任何時候的流程的時候進行發(fā)起read操作,因為我們的volatile的鎖只是鎖了在wirte的寫流程

不保證原子性

  • 從底層來說,i++或者number++(在執(zhí)行引擎操作時)其實是分了三步的:數(shù)據(jù)加載 、數(shù)據(jù)計算數(shù)據(jù)賦值 。而這三步非原子操作

第六章volatile詳解

  • 對于volatile變量具備可見性 ,JVM只是保證從主內(nèi)存加載到線程工作內(nèi)存的值是最新的,也僅是數(shù)據(jù)加載時是最新的。
  • 但是多線程環(huán)境下,“數(shù)據(jù)計算”和“數(shù)據(jù)賦值”操作可能多次出現(xiàn),若數(shù)據(jù)在加載之后,若主內(nèi)存volatile修飾變量發(fā)生修改之后,線程工作內(nèi)存中的操作將會作廢去讀主內(nèi)存最新值,操作出現(xiàn)寫丟失問題。即各線程私有內(nèi)存和主內(nèi)存公共內(nèi)存中變量不同步 ,進而導致數(shù)據(jù)不一致。由此可見volatile解決的是變量讀取時的可見性問題,但無法保證原子性,對于多線程修改主內(nèi)存共享變量的場景必須使用加鎖同步。
  • 就比如這個i++操作,當你從主內(nèi)存加載了5進入,并且加載進了工作內(nèi)存,正當要進行++操作的時候,線程2進行了讀取操作,也是從主內(nèi)存讀取了5,因為線程1沒有進行write操作,所有主內(nèi)存還是最新的值,符合volatile的特性,然后線程進行了8個一套操作,然后變成6寫入主內(nèi)存,線程1的5就失效了,就需要進行重新從內(nèi)存讀取到6,但是這次++操作是丟失了,所有還是線程不安全的

結(jié)論

  • volatile不適合參與到依賴當前值的運算,如i=i+1,i++之類的
  • 那么依靠可見性的特點volatile可以用在哪些地方呢?通常volatile用作保存某個狀態(tài)的boolean值或or int值。 (一旦布爾值被改變迅速被看到,就可以做其他操作)

禁止指令重排

  • 重排序是指編譯器和處理器為了優(yōu)化程序性能而對指令序列進行重新排序的一種手段,有時候會改變程序語句的先后順序

  • 不存在數(shù)據(jù)依賴關(guān)系,可以重排序;

  • 存在數(shù)據(jù)依賴關(guān)系 ,禁止重排序

    • 數(shù)據(jù)依賴性 :若兩個操作訪問同一變量,且這兩個操作中有一個為寫操作,此時兩操作間就存在數(shù)據(jù)依賴性。

但重排后的指令絕對不能改變原有的串行語義!這點在并發(fā)設計中必須要重點考慮!

數(shù)據(jù)依賴的實例

第六章volatile詳解

  • 不存在數(shù)據(jù)依賴關(guān)系,可以重排序 ===> 重排序OK 。
  • 存在數(shù)據(jù)依賴關(guān)系,禁止重排序===> 重排序發(fā)生,會導致程序運行結(jié)果不同。
  • 編譯器和處理器在重排序時,會遵守數(shù)據(jù)依賴性,不會改變存在依賴關(guān)系的兩個操作的執(zhí)行,但不同處理器和不同線程之間的數(shù)據(jù)性不會被編譯器和處理器考慮,其只會作用于單處理器和單線程環(huán)境

如何正確使用volatile(實際工作)

單一賦值可以,但是含有符合運算賦值不可以(比如i++)

  • 下面這兩個單一賦值可以的

    • volatile int a = 10;

    • volatile boolean flag = false

狀態(tài)標志,判斷業(yè)務是否結(jié)束

//這個前面講過
public class UseVolatileDemo{
    private volatile static boolean flag = true;

    public static void main(String[] args){
        new Thread(() -> {
            while(flag) {
                //do something......循環(huán)
            }
        },"t1").start();

        //暫停幾秒鐘線程
        try { TimeUnit.SECONDS.sleep(2L); } catch (InterruptedException e) { e.printStackTrace(); }

        new Thread(() -> {
            flag = false;
        },"t2").start();
    }
}


開銷較低的讀,寫鎖策略

當讀遠多于寫

  • 最土的方法就是加兩個synchronized,但是讀用volatile,寫用synchronized可以提高性能
public class UseVolatileDemo{
    //
   // 使用:當讀遠多于寫,結(jié)合使用內(nèi)部鎖和 volatile 變量來減少同步的開銷
   // 理由:利用volatile保證讀取操作的可見性;利用synchronized保證復合操作的原子性
     
    public class Counter {
        private volatile int value;

        public int getValue(){
            return value;   //利用volatile保證讀取操作的可見性
         }
        public synchronized int increment(){
            return value++; //利用synchronized保證復合操作的原子性
        }
    }
}

單例模式雙重鎖案例

public class SafeDoubleCheckSingleton
{
    private static SafeDoubleCheckSingleton singleton; //-----這里沒加volatile
    //私有化構(gòu)造方法
    private SafeDoubleCheckSingleton(){
    }
    //雙重鎖設計
    public static SafeDoubleCheckSingleton getInstance(){
        if (singleton == null){
            //1.多線程并發(fā)創(chuàng)建對象時,會通過加鎖保證只有一個線程能創(chuàng)建對象
            synchronized (SafeDoubleCheckSingleton.class){
                if (singleton == null){
                    //隱患:多線程環(huán)境下,由于重排序,該對象可能還未完成初始化就被其他線程讀取
                    singleton = new SafeDoubleCheckSingleton();
                    //實例化分為三步
                    //1.分配對象的內(nèi)存空間
                    //2.初始化對象
                    //3.設置對象指向分配的內(nèi)存地址
                }
            }
        }
        //2.對象創(chuàng)建完畢,執(zhí)行g(shù)etInstance()將不需要獲取鎖,直接返回創(chuàng)建對象
        return singleton;
    }
}

單線程情況下

  • 單線程環(huán)境下(或者說正常情況下),在"問題代碼處",會執(zhí)行如下操作,保證能獲取到已完成初始化的實例
//三步
memory = allocate(); //1.分配對象的內(nèi)存空間
ctorInstance(memory); //2.初始化對象
instance = memory; //3.設置對象指向分配的內(nèi)存地址

多線程情況下(由于指令重排序)
隱患:多線程環(huán)境下,在"問題代碼處",會執(zhí)行如下操作,由于重排序?qū)е?,3亂序,后果就是其他線程得到的是null而不是完成初始化的對象 。(沒初始化完的就是null)

正常情況

//三步
memory = allocate(); //1.分配對象的內(nèi)存空間
ctorInstance(memory); //2.初始化對象
instance = memory; //3.設置對象指向分配的內(nèi)存地址

非正常情況

//三步
memory = allocate(); //1.分配對象的內(nèi)存空間
instance = memory; //3.設置對象指向分配的內(nèi)存地址---這里指令重排了,但是對象還沒有初始化
ctorInstance(memory); //2.初始化對象

解決

  • 加volatile修飾
public class SafeDoubleCheckSingleton
{
    //通過volatile聲明,實現(xiàn)線程安全的延遲初始化。
    private volatile static SafeDoubleCheckSingleton singleton;
    //私有化構(gòu)造方法
    private SafeDoubleCheckSingleton(){
    }
    //雙重鎖設計
    public static SafeDoubleCheckSingleton getInstance(){
        if (singleton == null){
            //1.多線程并發(fā)創(chuàng)建對象時,會通過加鎖保證只有一個線程能創(chuàng)建對象
            synchronized (SafeDoubleCheckSingleton.class){
                if (singleton == null){
                    //隱患:多線程環(huán)境下,由于重排序,該對象可能還未完成初始化就被其他線程讀取
                                      //原理:利用volatile,禁止 "初始化對象"(2) 和 "設置singleton指向內(nèi)存空間"(3) 的重排序
                    singleton = new SafeDoubleCheckSingleton();
                }
            }
        }
        //2.對象創(chuàng)建完畢,執(zhí)行g(shù)etInstance()將不需要獲取鎖,直接返回創(chuàng)建對象
        return singleton;
    }
}


實例化singleton分多步執(zhí)行(分配內(nèi)存空間、初始化對象、將對象指向分配的內(nèi)存空間),某些編譯器為了性能原因,會將第二步和第三步進行重排序(java分配內(nèi)存空間、將對象指向分配的內(nèi)存空間、初始化對象)。這樣,某個線程可能會獲得一個未完全初始化的實例。

面試回答

valatile可見性

  • 寫操作的話,這個變量的最新值會立即刷新到主內(nèi)存中
  • 讀操作的話,總是能夠讀取這個變量的最新值,也就是這個變量最后被修改的值
  • 某個線程收到通知,去讀取volatile修飾的變量的值的時候,線程私有工作內(nèi)存的數(shù)據(jù)失效,需要重新回到主內(nèi)存區(qū)讀取最新的數(shù)據(jù)

內(nèi)存屏障是什么?

內(nèi)存屏障是一種屏障指令,它使得CPU或編譯器對屏障指令的前和后所發(fā)出的內(nèi)存操作執(zhí)行一個排序的約束。也叫內(nèi)存柵欄或柵欄指令

內(nèi)存屏障能干嘛?

  • 阻止屏障兩邊的指令重排序
  • 寫數(shù)據(jù)時假如屏障,強制將線程私有工作內(nèi)存的數(shù)據(jù)刷回主物理內(nèi)存
  • 讀數(shù)據(jù)時加入屏障,線程私有工作內(nèi)存的數(shù)據(jù)失效,重新到主物理內(nèi)存中獲取最新數(shù)據(jù)

內(nèi)存屏障的四大指令

  • 在每一個volatile寫操作前面插入一個StoreStore屏障
    • 普通寫和volatile寫禁止重排
  • 在每一個volatile寫操作后面插入一個StoreLoad屏障
    • volatile寫和普通讀禁止重排
  • 在每一個volatile讀操作后面插入一個LoadLoad屏障
    • volatile讀和普通讀禁止重排
  • 在每一個volatile讀操作后面插入一個LoadStore屏障
    • volatile讀和volatile寫進行重排

3句話總結(jié)文章來源地址http://www.zghlxwxcb.cn/news/detail-486716.html

  • volatile寫之前的的操作,都禁止重排到volatile之后
  • volatile讀之后的操作,都禁止重排到volatile之前
  • volatile寫之后volatile讀,禁止重排序

到了這里,關(guān)于第六章volatile詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務器費用

相關(guān)文章

  • DCL 單例模式設計為什么需要 volatile 修飾實例對象

    DCL 單例模式設計為什么需要 volatile 修飾實例對象

    ?DCL 問題,是在基于雙重檢查鎖設計下的單例模式中,存在不 完整對象的問題。而這個不完整對象的本質(zhì),是因為指令重排序?qū)е碌摹?當我們使用 instance=new DCLExample()構(gòu)建一個實例對象的時候,因為 new 這個操作并不是原子的。所以這段代碼最終會被編譯成 3 條指令: 為對象

    2024年02月08日
    瀏覽(31)
  • FPGA設計Verilog基礎(chǔ)之數(shù)據(jù)類型的作用和特點、常量和變量的代碼示例詳解

    FPGA設計Verilog基礎(chǔ)之數(shù)據(jù)類型的作用和特點、常量和變量的代碼示例詳解

    注意:后續(xù)技術(shù)分享,第一時間更新,以及更多更及時的技術(shù)資訊和學習技術(shù)資料 ,將在公眾號 CTO Plus 發(fā)布,請關(guān)注公眾號: CTO Plus 在Verilog中,有多種數(shù)據(jù)類型可供使用,包括位向量類型、整數(shù)類型、實數(shù)類型、布爾型、時間類型和字符串類型等。下面詳細介紹Verilog的所

    2024年02月03日
    瀏覽(25)
  • 第六章:string類

    第六章:string類

    string是字符序列的類 C++文檔 C語言中,字符串是以’\\0’結(jié)尾的一些字符的集合,為了操作方便,C標準庫中提供了一些str系列的庫函數(shù),但是這些庫函數(shù)與字符串是分離開的,不太符合OOP的思想,而且底層空間需要用戶自己管理,稍不留神可能還會越界訪問。 ASCII (American S

    2024年02月17日
    瀏覽(22)
  • 第六章 Element UI

    第六章 Element UI

    內(nèi)容來源于藍橋杯競賽,自己根據(jù)這個題綱重新鞏固下前端的知識 Container布局 布局實現(xiàn)方式,首先刪除App.vue冗余代碼,創(chuàng)建container文件定義布局模式,App.vue種引入布局模式。 1. 上下布局 2.上中下布局 3. 左右布局 4.上-下(左右)布局 5.上-下(左右(上下))布局 6.左右(

    2024年02月06日
    瀏覽(19)
  • 第六章 Linux 磁盤管理

    第六章 Linux 磁盤管理

    如果我們想在系統(tǒng)中增加一塊硬盤用于數(shù)據(jù)存取,那么大概需要以下步驟: 目的,一是為了分割硬盤空間方便管理,更重要的是讓各個分區(qū)都基本獨立開來,這樣如果某個區(qū)發(fā)生問題,至少不會直接影響到其他分區(qū)。 舉例:如果把一塊磁盤比喻成一大塊地,那么對磁盤進行

    2024年02月04日
    瀏覽(46)
  • Scala(第六章 面向?qū)ο螅? decoding=
  • Python第六章作業(yè)

    目錄 第1關(guān)?列表的屬性與方法 第2關(guān)?推導式與生成器 第3關(guān)?列表的合并與排序 第4關(guān)?二維列表排序 第5關(guān)?動物重量排序 第6關(guān)?身份證號升位 第7關(guān)?完美立方數(shù) 第8關(guān)?約瑟夫環(huán)問題 第9關(guān)?文本分析(2)——統(tǒng)計英文文件中的單詞數(shù) 第1關(guān)?列表的屬性與方法 初始化一個空

    2024年02月05日
    瀏覽(48)
  • 第六章——分枝限界法

    第六章——分枝限界法

    分枝限界法和回溯法一樣,也是一種在問題的解空間樹上搜可行解的窮舉算法。 其中“分枝”指的是“分枝限界法”搜索可行解采用的策略為廣度優(yōu)先搜索或?qū)崿F(xiàn)方法和思路類似的代價優(yōu)先搜索。 廣度優(yōu)先搜索的概念和實現(xiàn)前面已經(jīng)介紹過很多次了,這里不再做贅述;代價

    2024年02月09日
    瀏覽(30)
  • 數(shù)據(jù)結(jié)構(gòu):第六章 圖

    數(shù)據(jù)結(jié)構(gòu):第六章 圖

    ps:圖不可以為空圖。 對于圖中的邊,兩頭必須要有結(jié)點。 邊集是可以沒有的,如上圖最右邊。 關(guān)于無向圖和有向圖的應用如下 比如你微信里的好友關(guān)系,你要和一個人建立關(guān)系(也就是圖的兩個結(jié)點連上),你只需要加1次就可以了,也不需要你加我,我還要加你。 具體

    2024年02月14日
    瀏覽(18)
  • 第六章代碼題(三)

    第六章代碼題(三)

    第一章代碼題_永無魘足的博客-CSDN博客 第二章代碼題(一)_永無魘足的博客-CSDN博客 第二章代碼題(二)_永無魘足的博客-CSDN博客 第二章代碼題(三)_永無魘足的博客-CSDN博客 第三章代碼題(一)_永無魘足的博客-CSDN博客 第三章代碼題(一)_永無魘足的博客-CSDN博客 第六

    2024年02月14日
    瀏覽(16)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包