摘要:今天開始整理學習多線程的知識,談談最重要的兩個關鍵字和。但是這樣一個過程比較慢,在使用多線程的時候就會出現問題。有序性有序性是指多線程執行結果的正確性。這種機制在多線程中會出現問題,因此可以通過來禁止重排。
今天開始整理學習多線程的知識,談談最重要的兩個關鍵字:volatile和synchronized。
一、三個特性 1、原子性所謂原子性操作就是指這些操作是不可中斷的,要么執行過程中不被中斷,要么不做。在Java中對基本數據類型的讀取和賦值操作是原子性操作,比如i++就不是原子性操作,分為三步:讀取i,i++,寫回。
2、可見性這個特性可以通過Java的內存模型來理解。
鏈接描述
Java的內存模型如上圖所示,可以看到,一個線程對變量進行操作時,首先需要將變量從主存拷貝一個副本到工作內存中,操作完之后再給工作內存中的變量賦值,再傳回主存。但是這樣一個過程比較慢,在使用多線程的時候就會出現問題。
而所謂的內存可見性,就是在使用volatile關鍵字之后,對變量的修改會立即刷回主存。
3、有序性有序性是指多線程執行結果的正確性。這里介紹一下指令重排的概念。
指令重排:這一機制是指JMM允許對指令進行重排,但是這種重排不會影響程序的結果。比如a++; b++;兩條指令之間沒有聯系,因此可以調換順序。
這種機制在多線程中會出現問題,因此可以通過volatile來禁止重排。
(1)保證了不同線程對被修飾變量操作的內存可見性
(2)禁止了指令的重排序
從內存的語義上看,寫volatile變量時,會將更新的值直接寫回到主存;讀volatile變量時,會直接從主存中讀取變量。
2、volatile關鍵字的特點volatile關鍵字可以保證有序性和可見性,但是無法保證原子性。
舉一個例子,現在內存中有一個count為0,現在A進程和B進程想對count做加一操作,首先A和B都將count取出,A和B的工作內存中的count值都為0,此時A做加一操作,并寫回主存,而B也只會對0做加一操作,因為B已經讀完了,他并不知道主存中的count已經被修改過了,因此可見無法保證原子性。
3、volatile的底層實現volatile主要是通過lock指令前綴來實現的:
(1)重排序時不能把后面的指令重排到前面
(2)使本CPU的cache寫入主存
(3)寫入時,其他CPU的cache無效,也就是直接從主存中讀取,對外部可見
(1)一個非常直觀的解釋是:
Java語言的關鍵字,當它用來修飾一個方法或者一個代碼塊的時候,能夠保證在同一時刻最多只有一個線程執行該段代碼。
(2)官方的解釋是:
Java中的synchronized,通過使用內置鎖,來實現對變量的同步操作,進而實現了對變量操作的原子性和其他線程對變量的可見性,從而確保了并發情況下的線程安全。
比起volatile關鍵字,synchronized關鍵字不僅能夠保證可見性,還可以保持原子性。
3、實現synchronized關鍵字的原理,就是通過鎖,線程拿到鎖之后,其他線程就會阻塞等待。
在Java中每一個對象都有一個與之關聯的鎖,稱為內置鎖:
當我們使用synchronized修飾非靜態方法時,用的是調用該方法的實例的內置鎖,也就是this;
當我們使用synchronized修飾靜態方法時,用的是調用該方法的所在的類對象的內置鎖;
更多時候,我們使用的是synchronized代碼塊,我們經常用的是synchronized(this),也就是把對象實例作為鎖。如下
public void process() { doProcess(); synchronized (this) { count ++; } }4、重入問題
public class Widget { public synchronized void doSomething() { ... } } public class LoggingWidget extends Widget { public synchronized void doSomething() { System.out.println(toString() + ": calling doSomething"); super.doSomething(); } }
值得注意的是,在這個程序中,兩個doSomething函數都有synchronized關鍵字,那么在執行過程中是否會發生死鎖呢,答案是否定的,因為獲得鎖的是線程,因此這兩個函數都用的是同一個鎖,因此又稱為可重入鎖
參考:
https://hzy38324.gitbooks.io/... 《Java并發編程實踐》
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/75131.html
摘要:如果把注釋去掉,則在所以非線程都結束時,自動終止。默認所有從線程產生的線程也是線程。停止線程線程完成方法后,就進入狀態。被標示為的區塊會被監控,任何線程要執行區塊都必須先獲得指定的對象鎖定。 Tread和Runnable 定義線程 實現Runnable接口,重寫run()方法 繼承Thread類,重寫run()方法 啟動線程 Runnable tortoise=ne...
摘要:多線程是一個龐大的知識體系,這里對其中的進行一個總結,理清他的來龍去脈。替換重量級鎖在中又稱為重量級鎖,能夠保重的幾大特性一致性,原子性,可見性。 Java多線程是一個龐大的知識體系,這里對其中的volatile進行一個總結,理清他的來龍去脈。 CPU緩存 要搞懂volatile,首先得了解CPU在運行過程中的存儲是如何處理的,其結構如圖 showImg(https://segment...
摘要:在之前的文章中學習了關鍵字,可以保證變量在線程間的可見性,但他不能真正的保證線程安全。線程執行到指令時,將會嘗試獲取對象所對應的的所有權,即嘗試獲得對象的鎖。從可見性上來說,線程通過持有鎖的方式獲取變量的最新值。 在之前的文章中學習了volatile關鍵字,volatile可以保證變量在線程間的可見性,但他不能真正的保證線程安全。 /** * @author cenkailun *...
摘要:簡介是的線程安全版本,內部也是使用數組鏈表紅黑樹的結構來存儲元素。相比于同樣線程安全的來說,效率等各方面都有極大地提高。中的關鍵字,內部實現為監視器鎖,主要是通過對象監視器在對象頭中的字段來表明的。 簡介 ConcurrentHashMap是HashMap的線程安全版本,內部也是使用(數組 + 鏈表 + 紅黑樹)的結構來存儲元素。 相比于同樣線程安全的HashTable來說,效率等各方...
摘要:當線程執行完后進入狀態,表示線程執行結束。其中和表示兩個線程。但要注意,讓出并不表示當前線程不執行了。關鍵字其作用是防止指令重排和使線程對一個對象的修改令其他線程可見。 JMM特性一覽 Java Memory Model的關鍵技術點都是圍繞著多線程的原子性、可見性和有序性來建立的。因此我們首先需要來了解這些概念。 原子性(Atomicity) 原子性是指一個操作是不可中斷的。即使是在多...
閱讀 1911·2021-11-09 09:46
閱讀 2489·2019-08-30 15:52
閱讀 2450·2019-08-30 15:47
閱讀 1324·2019-08-29 17:11
閱讀 1749·2019-08-29 15:24
閱讀 3505·2019-08-29 14:02
閱讀 2446·2019-08-29 13:27
閱讀 1203·2019-08-29 12:32