java中什么是線程不安全給出一個(gè)例子

下面我們?cè)俳o出一個(gè)線程不安全的例子。
馬克- to-win:馬克 java社區(qū):防盜版實(shí)名手機(jī)尾號(hào): 73203。



例:1.8.2-本章源碼

class BookMark_to_win {
    int bookNum=10;
    void onlySellOne() {
        if (bookNum > 0) {
            System.out.println(Thread.currentThread().getName()
                    + " before" + bookNum);
            bookNum--;
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
            }
            System.out.println(Thread.currentThread().getName()
                    + " after " + bookNum);
        }
    }
}
public class Test {
    public static void main(String[] args) {
        BookMark_to_win bookM = new BookMark_to_win();
        while (bookM.bookNum>0) {
            bookM.onlySellOne();
        }
    }
}

輸出結(jié)果:

main before10
main after 9
main before9
main after 8
main before8
main after 7
main before7
main after 6
main before6
main after 5
main before5
main after 4
main before4
main after 3
main before3
main after 2
main before2
main after 1
main before1
main after 0

后續(xù):在以上的例子中,我們編了一個(gè)方法叫onlySellOne。這個(gè)方法的目的就是每一次只賣(mài)一本書(shū)。單線程的環(huán)境下,我們看到結(jié)果符合我們的預(yù)期。下面我們就把它放在一個(gè)多線程的環(huán)境下測(cè)試。

馬克-to-win:下面的例子是比較明顯的,本來(lái)說(shuō)好了,if (bookNum > 0)的話,我才買(mǎi)書(shū),因?yàn)闆](méi)有書(shū),賣(mài)什么?而現(xiàn)在卻把書(shū)賣(mài)出了負(fù)數(shù),這已經(jīng)明顯不符合邏輯了。要是銀行賬號(hào)的話,你的賬號(hào)就能成為負(fù)值,意味著你花了銀行的錢(qián)。只要方法中有關(guān)鍵變量又有判斷還要改變此變量,線程安全的錯(cuò)誤就會(huì)比較邪乎!(比如單態(tài)中也有判斷)沒(méi)判斷,雖然也錯(cuò),不那么邪乎!




例:1.8.2_b-本章源碼

class BookMark_to_win {
    int bookNum=1;
    void onlySellOne() {
        if (bookNum > 0) {
            System.out.println(Thread.currentThread().getName()
                    + " before" + bookNum);
            bookNum--;
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
            }
            System.out.println(Thread.currentThread().getName()
                    + " after " + bookNum);
        }
    }
}
class MyThread extends Thread {
    BookMark_to_win book;
    MyThread(BookMark_to_win tmp) {
        this.book = tmp;
    }
    public void run() {   
        while (book.bookNum>0) {
            book.onlySellOne();
        }
    }
}
public class Test {
    public static void main(String[] args) {
        BookMark_to_win bookM = new BookMark_to_win();
        Thread t1 = new MyThread(bookM);
        Thread t2 = new MyThread(bookM);
        t1.start();
        t2.start();
    }
}

輸出結(jié)果:

Thread-0 before1
Thread-1 before1
Thread-1 after -1
Thread-0 after -1

后續(xù):我們仔細(xì)觀察會(huì)發(fā)現(xiàn):Thread-0 before1          Thread-0 after -1,線程0之前讀出有1本書(shū),調(diào)用了onlySellOne后,里面只做了一次"bookNum--"操作,發(fā)現(xiàn)結(jié)果是“Thread-0 after -1”即為還剩-1本書(shū)。為什么1-1=-1呢?原來(lái)線程0調(diào)用onlySellOne的"bookNum--";時(shí),線程1正好也執(zhí)行到這,調(diào)用了"bookNum--"; 所以實(shí)際上是1-1-1=-1;既然我們預(yù)期"bookNum--"是每次只賣(mài)一本書(shū),單線程環(huán)境執(zhí)行挺好,而在多線程環(huán)境下,得到了一次減兩本的結(jié)果,典型屬于線程不安全。