多線程帶來的問題

我們經常說的,xxx在多線程環(huán)境下會出問題。那么究竟是什么原因會導致這些問題呢?

原子性

所謂原子性,就是不可以再被分割。對于一個具有原子性操作來說,就是在執(zhí)行這個操作的過程中不會插入其他的操作

int i = 5; //原子性操作
i++; //非原子性操作
/**
* i++ 相當于 i = i + 1;
* 其中包含了三個操作:
*  1). 讀取 i 的值
*  2). 對 i 加 1
*  3). 重新賦值給 i
*/

非原子性操作可能會出現(xiàn)的問題:比如 i 的值為1,如果在 i++ 的第二個操作的時候,有其他的線程插入進來對變量 i 做了其他的操作,那么 i++ 之后,i 的值就不會是 2 了。

可見性

可見性,就是說某個線程對于一個共享變量做了修改,其他線程能夠立刻發(fā)現(xiàn)。

boolean flag = true;
while (flag) {
    // do something...
}
/**
* 對于這段代碼,線程 A 在執(zhí)行while循環(huán)。此時,線程 B 將flag的值修改為false,線程 A 能夠馬上退出循環(huán)操作,就說明變量flag具有可見性。
*/

共享變量未滿足可見性可能會出現(xiàn)的問題

public class ThreadDemo {

    private static boolean flag = true;
    
    public static void main(String[] args) throws InterruptedException {
        //線程A 
        //當 flag == false 跳出循環(huán),線程執(zhí)行結束
        new Thread(() -> {
            while (flag) {
                //do something...
            }
        }).start(); 

        //防止線程B先啟動
        Thread.sleep(10);

        //線程B
        //在線程A啟動后,修改flag的值為false
        new Thread(() -> flag = false).start();
    }
}

此時程序不會運行結束,因為變量flag沒有滿足可見性,線程B對變量flag的修改操作,對于線程A是不可見的。

有序性

通俗來講就是,代碼并不一定會按照順序來執(zhí)行,java虛擬機在執(zhí)行的過程中可能會改變順序來提高性能,但是不會改變程序整體的運行結果。

(1) int a = 2; 
(2) int b = 3;
(3) int c = a + b;
(4) int d = 6;

就比如這四行代碼,(3)的執(zhí)行依賴于(1)和(2),所以,虛擬機在改變執(zhí)行順序的時候,不會把(1)或者(2)放到(3)后面去執(zhí)行,(4)跟其他三行沒有依賴關系。最終執(zhí)行的順序是,(1)(2)一定在(3)之前執(zhí)行,(4)可以在任意位置執(zhí)行。這么看來似乎有序性顯得不是太重要,可是在多線程的環(huán)境下就會發(fā)生問題。

//有兩個線程 A B
boolean isDone = false;
//線程A
new Thread(() -> {
  save(object); //假設做保存操作
  isDone = true;
}).start();
//線程B
new Thread(() -> {
  while (true) {
    if (isDone) {
      Object obj = getObject(); 
      //使用obj對象做后續(xù)的工作 
    }
  }
}).start();

上面是一段偽代碼,想表述的意思是,線程A做保存操作,然后設置標記變量isDone為true;線程B根據標記變量判斷線程A是否保存完畢,當isDone == true,就認為線程A已經保存完畢,然后取出線程A保存的對象,做后續(xù)的工作。

如果此時,線程A中發(fā)生了重排序的情況,線程A里面的兩行代碼交換了執(zhí)行的順序。而此時,設置了isDone的值,還沒有執(zhí)行save操作的時候,線程B開始執(zhí)行了,就會發(fā)生問題,線程B的get操作不會取到任何對象。

對于以上的三個問題,Java提供了關鍵字synchronized來解決。當然還有volatile以及jdk并發(fā)包里面的各種工具,后面的文章我會介紹相關的知識

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 進程和線程 進程 所有運行中的任務通常對應一個進程,當一個程序進入內存運行時,即變成一個進程.進程是處于運行過程中...
    勝浩_ae28閱讀 5,257評論 0 23
  • 接著上節(jié) mutex,本節(jié)主要介紹atomic的內容,練習代碼地址。本文參考http://www.cplusplu...
    jorion閱讀 74,088評論 1 14
  • 一、Python簡介和環(huán)境搭建以及pip的安裝 4課時實驗課主要內容 【Python簡介】: Python 是一個...
    _小老虎_閱讀 6,319評論 0 10
  • 線程是程序執(zhí)行的最小單元,多線程是指程序同一時間可以有多個執(zhí)行單元運行(這個與你的CPU核心有關)。 在java中...
    程序員技術圈閱讀 1,064評論 2 17
  • 線程池ThreadPoolExecutor corepoolsize:核心池的大小,默認情況下,在創(chuàng)建了線程池之后...
    irckwk1閱讀 863評論 0 0

友情鏈接更多精彩內容