線程有有序性和可見性
多個線程之間是不能直接傳遞數據交互的,它們之間的交互只能通過共享變量來實現。
在多個線程之間共享類的一個對象,這個對象是被創建在主內存(堆內存)中,每個線程都有自己的工作內存(線程棧),工作內存存儲了主內存對象的一個副本,當線程操作對象時,首先從主內存復制對象到工作內存中,然後執行代碼改變了值,最後用工作內存刷新主內存。
當一個對象在多個內存中都存在副本時,如果一個內存修改了共享變量,其它線程也應該能夠看到被修改後的值,此為可見性。
多個線程執行時,CPU對線程的調度是隨機的,我們不知道當前程序被執行到哪步就切換到了下一個線程。為保證線程有序執行此為有序性。
使用synchronized修飾的方法或者代碼塊可以看成是一個原子操作
每個鎖對象(JLS中叫monitor)都有兩個隊列,一個是就緒隊列,一個是阻塞隊列,就緒隊列存儲了將要獲得鎖的線程,阻塞隊列存儲了被阻塞的線程,當一個線程被喚醒(notify)後,才會進入到就緒隊列,等待CPU的調度,反之,當一個線程被wait後,就會進入阻塞隊列,等待下一次被喚醒。看我們的例子,當第一個線程執行輸出方法時,獲得同步鎖,執行輸出方法,恰好此時第二個線程也要執行輸出方法,但發現同步鎖沒有被釋放,第二個線程就會進入就緒隊列,等待鎖被釋放。一個線程執行互斥代碼過程如下:
1. 獲得同步鎖;
2. 清空工作內存;
3. 從主內存拷貝對象副本到工作內存;
4. 執行代碼(計算或者輸出等);
5. 刷新主內存數據;
6. 釋放同步鎖。
所以,synchronized既保證了多線程的並發有序性,又保證了多線程的內存可見性。
volatile是第二種Java多線程同步的機制,一個變量可以被volatile修飾,在這種情況下內存模型(主內存和線程工作內存)確保所有線程可以看到一致的變量值。
線程有有序性和可見性