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é)果,典型屬于線程不安全。