前幾天羣裏有個小夥伴,年紀確實小,畢竟仍是大學生,很是好學,固然不是妹子~
我但是不只僅喜歡幫助妹子
先看他的代碼:程序員
類的命名,咱們就忽略了,畢竟小夥伴是真的在練習和測試。隨意起的類名。面試
類Test2繼承JFrame,是的,很古老的Java UI。忽略這個有年代感的類,瞧重點:編程
用Java畫了一個窗口,窗口上有個Big Button,鋪滿窗口的。這個類有一個變量b默認false,並給按鈕增長了一個事件,將b修改成true:緩存
public boolean b = false; ...忽略其餘代碼 button.addActionListener(new ActionListener(){ // 按鈕事件 public void actionPerformed(ActionEvent e){ // 修改b的值 b = true; } });
類Test1繼承的是一個線程,該線程進行死循環,判斷test2.b==true,則打印Hello world:ide
public void run(){ while(true){ if(test2.b){ System.out.println("Hello world"); } } }
main的實現邏輯是,實例化Test2,並傳入Test1構造函數,啓動Test1線程函數
public static void main(String[] args){ Test2 test2 = new Test2(); new Test1(test2).start(); }
下圖是這個代碼啓動後的全屏按鈕:性能
小夥伴說:爲何啓動後控制檯沒有打印Hello world?測試
我也同樣看了幾遍產生和小夥伴同樣的疑問---Hello world跑哪去了呢?spa
一切都是那麼完美無缺!線程
這個結果纔是咱們期待的奇蹟:
但是奇蹟並未發生!
Main線程修改了變量b的值,Test1線程讀取變量b的值
b爲mian線程和Test1線程共享變量 對,問題就處在共享變量上!!!!!
共享變量你們可以理解,畢竟共享時代也持續好久了~
但是這個變量真的共享嗎?
既然這麼問,那確定不是真的!納尼!!!!
CPU能挖礦,咱們知道性能特別快,若是頻繁跨硬件訪問主存,而且內存讀寫數據的速度要比CPU慢不少,若是是這樣的話,那CPU再快也是浪費!
因此CPU訪問內存變量採用了CPU內部的高速緩存來解決!
當程序在運行過程當中,會將運算須要的數據從主存複製一份到CPU的高速緩存當中,那麼CPU進行計算時就能夠直接從它的高速緩存讀取數據和向其中寫入數據,當運算結束以後,再將高速緩存中的數據刷新到主存當中。
標題如圖:
按照程序邏輯走一走:
@11 同窗,如今能理解了嗎?
不用擔憂,你遇到的問題,偉人已經爲咱們鋪好了路。
有兩種方式解決線程間的緩存一致性,專業表述是這樣的:
其實上面兩點通俗一點理解是這樣的:
第1點可理解爲,多個線程一個一個依次來讀取或修改變量,一個讀寫,另外的就要等待,也就是阻塞。明顯方案太out了。
偉人是接受不了的。
第二點是經過一個xx協議完成。這個xx協議就是我沒據說過的Intel 的MESI協議。 不想之後裝b,能夠不記下它的大名。
這個協議是幹嗎的呢?一個線程若是修改了一個共享變量
的值,注意是共享變量,若是其餘cpu的高速緩存有這個共享變量的副本,那麼就將它變成無效,若是其餘CPU發現無效,就從新從主存讀取。
TIP:若是以爲有點繞,能夠讀一遍。
使用Volatile關鍵字。姿式是這樣的!
public volatile boolean b = false;
到這裏,老司機能夠離場,這個是面試80%必問題。
固然,公衆號回覆msgq1
能夠下載《面試怪圈內卷手冊》
會教給你怎麼給面試官擺2小時的。
volatile關鍵字,有兩個重要的做用:
百度搜索volatile
第一個,真心講的不錯,若是你有耐心花2個小時,把它讀完:
迴歸正題了,仍是說一下volatile內存可見性是怎麼作到的:
1.若是Main線程修改了b的值爲true
2.會致使線程Test1中高速緩存的b的值失效
3.Test1讀取b的值得時候,發現已經失效,從新從主存中獲取最新值。
好了,花了兩個小時,解決了@11 朋友心中的困惑,但願他在編程的路上再也不迷路。
無論怎麼樣,可以在大學的時候,遇到這樣的問題,真的是給編程人生是很好的開始!
最近我整理了整套《JAVA核心知識點總結》,說實話 ,做爲一名Java程序員,不論你需不須要面試都應該好好看下這份資料。拿到手老是不虧的~個人很多粉絲也所以拿到騰訊字節快手等公司的Offer
進【Java進階之路羣】,找管理員獲取哦-!