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

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問題,去搜搜看,總會(huì)有你想問的

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

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

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

5 回答

?
慕村225694

TA貢獻(xiàn)1880條經(jīng)驗(yàn) 獲得超4個(gè)贊

鑒于這段代碼:

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;

? ? }

}

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


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


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

TA貢獻(xiàn)1862條經(jīng)驗(yàn) 獲得超7個(gè)贊

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

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

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

  3. 讓另一個(gè)線程,比方說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

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


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

TA貢獻(xiàn)1860條經(jīng)驗(yàn) 獲得超9個(gè)贊

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


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


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


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


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


@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();

        }


    }

}


我們可以使用信號(hào)量,也可以使用顯式鎖定。但是對(duì)于這個(gè)簡單的代碼,AtomicInteger 就足夠了


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

TA貢獻(xiàn)1826條經(jīng)驗(yàn) 獲得超6個(gè)贊

請(qǐng)?jiān)倏纯茨愕脑创a中是如何介紹這個(gè)例子的。

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

這個(gè)例子說明了多線程不是確定性的,因?yàn)槟悴荒鼙WC不同線程操作的執(zhí)行順序,這可能會(huì)導(dǎo)致多次運(yùn)行的不同觀察結(jié)果。但是并不能說明內(nèi)存一致性錯(cuò)誤!

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

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

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

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

要最終回答您的問題,請(qǐng)注意以下幾點(diǎn):

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

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

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

TA貢獻(xiàn)1818條經(jīng)驗(yàn) 獲得超7個(gè)贊

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

也許很簡單,但它對(duì)我有用。


查看完整回答
反對(duì) 回復(fù) 2023-05-24
  • 5 回答
  • 0 關(guān)注
  • 220 瀏覽

添加回答

舉報(bào)

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號(hào)

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