java中什么是线程不安全给出一个例子

下面我们再给出一个线程不安全的例子。
马克- to-win:马克 java社区:防盗版实名手机尾号: 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();
        }
    }
}

输出结果:

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

后续:在以上的例子中,我们编了一个方法叫onlySellOne。这个方法的目的就是每一次只卖一本书。单线程的环境下,我们看到结果符合我们的预期。下面我们就把它放在一个多线程的环境下测试。

马克-to-win:下面的例子是比较明显的,本来说好了,if (bookNum > 0)的话,我才买书,因为没有书,卖什么?而现在却把书卖出了负数,这已经明显不符合逻辑了。要是银行账号的话,你的账号就能成为负值,意味着你花了银行的钱。只要方法中有关键变量又有判断还要改变此变量,线程安全的错误就会比较邪乎!(比如单态中也有判断)没判断,虽然也错,不那么邪乎!




例: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();
    }
}

输出结果:

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

后续:我们仔细观察会发现:Thread-0 before1          Thread-0 after -1,线程0之前读出有1本书,调用了onlySellOne后,里面只做了一次"bookNum--"操作,发现结果是“Thread-0 after -1”即为还剩-1本书。为什么1-1=-1呢?原来线程0调用onlySellOne的"bookNum--";时,线程1正好也执行到这,调用了"bookNum--"; 所以实际上是1-1-1=-1;既然我们预期"bookNum--"是每次只卖一本书,单线程环境执行挺好,而在多线程环境下,得到了一次减两本的结果,典型属于线程不安全。