第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

多線程中內(nèi)存一致性錯誤的真實示例?

多線程中內(nèi)存一致性錯誤的真實示例?

子衿沉夜 2023-05-24 14:35:51
在java多線程的教程中,給出了一個Memory Consistency Errors的例子。但我無法重現(xiàn)它。還有其他方法可以模擬內(nèi)存一致性錯誤嗎?教程中提供的示例:假設(shè)定義并初始化了一個簡單的 int 字段:int?counter?=?0;計數(shù)器字段在兩個線程 A 和 B 之間共享。假設(shè)線程 A 遞增計數(shù)器:counter++;然后,不久之后,線程 B 打印出計數(shù)器:System.out.println(counter);如果這兩個語句在同一個線程中執(zhí)行,則可以安全地假設(shè)打印出的值是“1”。但是,如果這兩個語句在不同的線程中執(zhí)行,則打印出的值很可能是“0”,因為不能保證線程 A 對計數(shù)器的更改對線程 B 可見——除非程序員在兩者之間建立了 happens-before 關(guān)系這兩個聲明。
查看完整描述

5 回答

?
慕村225694

TA貢獻1880條經(jīng)驗 獲得超4個贊

鑒于這段代碼:

public class Test {

? ? volatile static private int a;

? ? static private int b;


? ? public static void main(String [] args) throws Exception {

? ? ? ? for (int i = 0; i < 100; i++) {

? ? ? ? ? ? new Thread() {


? ? ? ? ? ? ? ? @Override

? ? ? ? ? ? ? ? public void run() {

? ? ? ? ? ? ? ? ? ? int tt = b; // makes the jvm cache the value of b


? ? ? ? ? ? ? ? ? ? while (a==0) {


? ? ? ? ? ? ? ? ? ? }


? ? ? ? ? ? ? ? ? ? if (b == 0) {

? ? ? ? ? ? ? ? ? ? ? ? System.out.println("error");

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }


? ? ? ? ? ? }.start();

? ? ? ? }


? ? ? ? b = 1;

? ? ? ? a = 1;

? ? }

}

的易變存儲a發(fā)生在 的正常存儲之后b。因此,當(dāng)線程運行并看到時a != 0,由于 JMM 中定義的規(guī)則,我們必須看到b == 1。


JRE 中的 bug 允許線程進入生產(chǎn)error線并隨后得到解決。如果您沒有a定義為,這肯定會失敗volatile。


查看完整回答
反對 回復(fù) 2023-05-24
?
牧羊人nacy

TA貢獻1862條經(jīng)驗 獲得超7個贊

這可能會重現(xiàn)問題,至少在我的電腦上,我可以在一些循環(huán)后重現(xiàn)它。

  1. 假設(shè)你有一個Counter類:

    class Holder {
        boolean flag = false;
            long modifyTime = Long.MAX_VALUE;
    }
  2. 設(shè)為thread_Aflagtrue時間存入 modifyTime。

  3. 讓另一個線程,比方說thread_B,閱讀Counterflag。如果晚于thread_B仍然get even ,那么我們可以說我們已經(jīng)重現(xiàn)了問題。falsemodifyTime

示例代碼

class Holder {

    boolean flag = false;

    long modifyTime = Long.MAX_VALUE;

}


public class App {


    public static void main(String[] args) {

        while (!test());

    }


    private static boolean test() {


        final Holder holder = new Holder();


        new Thread(new Runnable() {

            @Override

            public void run() {

                try {

                    Thread.sleep(10);

                    holder.flag = true;

                    holder.modifyTime = System.currentTimeMillis();

                } catch (Exception e) {

                    e.printStackTrace();

                }

            }

        }).start();


        long lastCheckStartTime = 0L;

        long lastCheckFailTime = 0L;

        while (true) {

            lastCheckStartTime = System.currentTimeMillis();

            if (holder.flag) {

                break;

            } else {

                lastCheckFailTime = System.currentTimeMillis();

                System.out.println(lastCheckFailTime);

            }

        }


        if (lastCheckFailTime > holder.modifyTime 

                && lastCheckStartTime > holder.modifyTime) {

            System.out.println("last check fail time " + lastCheckFailTime);

            System.out.println("modify time          " + holder.modifyTime);

            return true;

        } else {

            return false;

        }

    }

}

結(jié)果


last check time 1565285999497

modify time     1565285999494

這意味著從提交的時間thread_B獲取,甚至將其設(shè)置為時間(早 3 毫秒)。falseCounterflag1565285999497thread_Atrue1565285999494


查看完整回答
反對 回復(fù) 2023-05-24
?
慕碼人2483693

TA貢獻1860條經(jīng)驗 獲得超9個贊

使用的示例太糟糕,無法證明內(nèi)存一致性問題。讓它工作將需要脆弱的推理和復(fù)雜的編碼。然而,您可能無法看到結(jié)果。多線程問題是由于時機不巧而發(fā)生的。如果有人想增加觀察問題的機會,我們需要增加不幸時機的機會。以下程序?qū)崿F(xiàn)了它。


public class ConsistencyIssue {


    static int counter = 0;


    public static void main(String[] args) throws InterruptedException {

        Thread thread1 = new Thread(new Increment(), "Thread-1");

        Thread thread2 = new Thread(new Increment(), "Thread-2");

        thread1.start();

        thread2.start();


        thread1.join();

        thread2.join();


        System.out.println(counter);

    }


    private static class Increment implements Runnable{


        @Override

        public void run() {

            for(int i = 1; i <= 10000; i++)

                counter++;

        }


    }

}

執(zhí)行1輸出:10963,執(zhí)行2輸出:14552


最終計數(shù)應(yīng)該是 20000,但它比那個少。原因是count++是多步操作,1.讀count 2.increment count 3.store it


兩個線程可能會同時讀取計數(shù) 1,將其遞增到 2。然后寫出 2。但如果它是串行執(zhí)行,則應(yīng)該是 1++ -> 2++ -> 3。


我們需要一種方法使所有 3 個步驟成為原子。即一次只能由一個線程執(zhí)行。


解決方案 1:Synchronized 用 Synchronized 包圍增量。由于計數(shù)器是靜態(tài)變量,您需要使用類級同步


@Override

        public void run() {

            for (int i = 1; i <= 10000; i++)

                synchronized (ConsistencyIssue.class) {

                    counter++;

                }

        }

現(xiàn)在輸出:20000


解決方案 2:AtomicInteger


public class ConsistencyIssue {


    static AtomicInteger counter = new AtomicInteger(0);


    public static void main(String[] args) throws InterruptedException {

        Thread thread1 = new Thread(new Increment(), "Thread-1");

        Thread thread2 = new Thread(new Increment(), "Thread-2");

        thread1.start();

        thread2.start();


        thread1.join();

        thread2.join();

        System.out.println(counter.get());

    }


    private static class Increment implements Runnable {


        @Override

        public void run() {

            for (int i = 1; i <= 10000; i++)

                counter.incrementAndGet();

        }


    }

}


我們可以使用信號量,也可以使用顯式鎖定。但是對于這個簡單的代碼,AtomicInteger 就足夠了


查看完整回答
反對 回復(fù) 2023-05-24
?
躍然一笑

TA貢獻1826條經(jīng)驗 獲得超6個贊

請再看看你的源代碼中是如何介紹這個例子的。

避免內(nèi)存一致性錯誤的關(guān)鍵是理解 happens-before 關(guān)系。這種關(guān)系只是保證一個特定語句對內(nèi)存的寫入對另一個特定語句可見。要看到這一點,請考慮以下示例。

這個例子說明了多線程不是確定性的,因為你不能保證不同線程操作的執(zhí)行順序,這可能會導(dǎo)致多次運行的不同觀察結(jié)果。但是并不能說明內(nèi)存一致性錯誤!

要了解什么是內(nèi)存一致性錯誤,您需要首先了解內(nèi)存一致性。Lamport 在 1979 年引入了最簡單的內(nèi)存一致性模型。這是原始定義。

任何執(zhí)行的結(jié)果都是一樣的,就好像所有進程的操作都按某種順序執(zhí)行,并且每個進程的操作都按照其程序指定的順序出現(xiàn)在這個序列中

現(xiàn)在,考慮這個示例多線程程序,請看一下最近一篇關(guān)于順序一致性的研究論文中的這張圖片。它說明了真正的內(nèi)存一致性錯誤可能是什么樣子。

http://img4.sycdn.imooc.com/646db0ad00015dac04930340.jpg

要最終回答您的問題,請注意以下幾點:

  1. 內(nèi)存一致性錯誤始終取決于底層內(nèi)存模型(特定的編程語言可能允許更多行為以進行優(yōu)化)。什么是最好的內(nèi)存模型仍然是一個懸而未決的研究問題。

  2. 上面給出的例子給出了一個違反順序一致性的例子,但是不能保證你可以用你喜歡的編程語言觀察到它,原因有兩個:它取決于編程語言精確的內(nèi)存模型,并且由于不確定性,你沒有強制執(zhí)行特定錯誤執(zhí)行的方法。

查看完整回答
反對 回復(fù) 2023-05-24
?
qq_笑_17

TA貢獻1818條經(jīng)驗 獲得超7個贊

有時當(dāng)我試圖重現(xiàn)一些真正的并發(fā)問題時,我會使用調(diào)試器。在 print 上創(chuàng)建一個斷點,在 increment 上創(chuàng)建一個斷點并運行整個過程。釋放不同順序的斷點會得到不同的結(jié)果。

也許很簡單,但它對我有用。


查看完整回答
反對 回復(fù) 2023-05-24
  • 5 回答
  • 0 關(guān)注
  • 193 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學(xué)習(xí)伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號