更多課程 選擇中心
        Java培訓

        400-111-8989

        Java培訓 > Java教程  > 正文

        關于Java并發編程的總結和思考

        • 發布:Java培訓
        • 來源:Java教程
        • 時間:2017-06-09 15:21

        【關于Java并發編程的總結和思考】

        為什么需要并發

        并發其實是一種解耦合的策略,它幫助我們把做什么(目標)和什么時候做(時機)分開。這樣做可以明顯改進應用程序的吞吐量(獲得更多的CPU調度時間)和結構(程序有多個部分在協同工作)。

        做過Java Web 開發的人都知道,Java Web中的Servlet程序在Servlet容器的支持下采用單實例多線程的工作模式,Servlet容器為你處理了并發問題。

        誤解和正解

        最常見的對并發編程的誤解有以下這些:

        -并發總能改進性能(并發在CPU有很多空閑時間時能明顯改進程序的性能,但當線程數量較多的時候,線程間頻繁的調度切換反而會讓系統的性能下降)

        -編寫并發程序無需修改原有的設計(目的與時機的解耦往往會對系統結構產生巨大的影響)

        -在使用Web或EJB容器時不用關注并發問題(只有了解了容器在做什么,才能更好的使用容器)

        下面的這些說法才是對并發客觀的認識:

        - 編寫并發程序會在代碼上增加額外的開銷

        - 正確的并發是非常復雜的,即使對于很簡單的問題

        - 并發中的缺陷因為不易重現也不容易被發現

        - 并發往往需要對設計策略從根本上進行修改

        并發編程的原則和技巧

        單一職責原則

        分離并發相關代碼和其他代碼(并發相關代碼有自己的開發、修改和調優生命周期)。

        限制數據作用域

        兩個線程修改共享對象的同一字段時可能會相互干擾,導致不可預期的行為,解決方案之一是構造臨界區,但是必須限制臨界區的數量。

        使用數據副本

        數據副本是避免共享數據的好方法,復制出來的對象只是以只讀的方式對待。Java 5的java.util.concurrent包中增加一個名為CopyOnWriteArrayList的類,它是List接口的子類型,所以你可以認為它是ArrayList的線程安全的版本,它使用了寫時復制的方式創建數據副本進行操作來避免對共享數據并發訪問而引發的問題。

        線程應盡可能獨立

        讓線程存在于自己的世界中,不與其他線程共享數據。有過Java Web開發經驗的人都知道,Servlet就是以單實例多線程的方式工作,和每個請求相關的數據都是通過Servlet子類的service方法(或者是doGet或doPost方法)的參數傳入的。

        只要Servlet中的代碼只使用局部變量,Servlet就不會導致同步問題。springMVC的控制器也是這么做的,從請求中獲得的對象都是以方法的參數傳入而不是作為類的成員,很明顯Struts 2的做法就正好相反,因此Struts 2中作為控制器的Action類都是每個請求對應一個實例。

        Java 5以前的并發編程

        Java的線程模型建立在搶占式線程調度的基礎上,也就是說:

        -所有線程可以很容易的共享同一進程中的對象。

        -能夠引用這些對象的任何線程都可以修改這些對象。

        -為了保護數據,對象可以被鎖住。

        Java基于線程和鎖的并發過于底層,而且使用鎖很多時候都是很萬惡的,因為它相當于讓所有的并發都變成了排隊等待。

        在Java 5以前,可以用synchronized關鍵字來實現鎖的功能,它可以用在代碼塊和方法上,表示在執行整個代碼塊或方法之前線程必須取得合適的鎖。

        對于類的非靜態方法(成員方法)而言,這意味這要取得對象實例的鎖,對于類的靜態方法(類方法)而言,要取得類的Class對象的鎖,對于同步代碼塊,程序員可以指定要取得的是那個對象的鎖。

        不管是同步代碼塊還是同步方法,每次只有一個線程可以進入,如果其他線程試圖進入(不管是同一同步塊還是不同的同步塊),JVM會將它們掛起(放入到等鎖池中)。這種結構在并發理論中稱為臨界區(critical section)。

        這里我們可以對Java中用synchronized實現同步和鎖的功能做一個總結:

        - 只能鎖定對象,不能鎖定基本數據類型

        - 被鎖定的對象數組中的單個對象不會被鎖定

        - 同步方法可以視為包含整個方法的synchronized(this) { … }代碼塊

        - 靜態同步方法會鎖定它的Class對象

        - 內部類的同步是獨立于外部類的

        - synchronized修飾符并不是方法簽名的組成部分,所以不能出現在接口的方法聲明中

        - 非同步的方法不關心鎖的狀態,它們在同步方法運行時仍然可以得以運行

        - synchronized實現的鎖是可重入的鎖。

        在JVM內部,為了提高效率,同時運行的每個線程都會有它正在處理的數據的緩存副本,當我們使用synchronzied進行同步的時候,真正被同步的是在不同線程中表示被鎖定對象的內存塊(副本數據會保持和主內存的同步,現在知道為什么要用同步這個詞匯了吧)。

        簡單的說就是在同步塊或同步方法執行完后,對被鎖定的對象做的任何修改要在釋放鎖之前寫回到主內存中;在進入同步塊得到鎖之后,被鎖定對象的數據是從主內存中讀出來的,持有鎖的線程的數據副本一定和主內存中的數據視圖是同步的。

        在Java最初的版本中,就有一個叫volatile的關鍵字,它是一種簡單的同步的處理機制,因為被volatile修飾的變量遵循以下規則:

        - 變量的值在使用之前總會從主內存中再讀取出來。

        - 對變量值的修改總會在完成之后寫回到主內存中。

        使用volatile關鍵字可以在多線程環境下預防編譯器不正確的優化假設(編譯器可能會將在一個線程中值不會發生改變的變量優化成常量),但只有修改時不依賴當前狀態(讀取時的值)的變量才應該聲明為volatile變量。

        不變模式也是并發編程時可以考慮的一種設計。讓對象的狀態是不變的,如果希望修改對象的狀態,就會創建對象的副本并將改變寫入副本而不改變原來的對象,這樣就不會出現狀態不一致的情況,因此不變對象是線程安全的。

        Java中我們使用頻率極高的String類就采用了這樣的設計。說到這里你可能也體會到final關鍵字的重要意義了。

        感謝大家的閱讀關注 更多精彩內容請關注Java培訓官網

        預約申請免費試聽課

        填寫下面表單即可預約申請免費試聽!怕錢不夠?可就業掙錢后再付學費! 怕學不會?助教全程陪讀,隨時解惑!擔心就業?一地學習,可全國推薦就業!

        上一篇:Java多線程之synchronized關鍵字詳解
        下一篇:2017年高考填報志愿選擇IT行業的五大理由
        • 掃碼領取資料

          回復關鍵字:視頻資料

          免費領取 達內課程視頻學習資料

        • 視頻學習QQ群

          添加QQ群:1143617948

          免費領取達內課程視頻學習資料

        Copyright ? 2021 Tedu.cn All Rights Reserved 京ICP備08000853號-56 京公網安備 11010802029508號 達內時代科技集團有限公司 版權所有

        選擇城市和中心
        貴州省

        福建省

        • 達內廈門軟件園中心
        廣西省

        海南省

        国产高清情侣视频2019年,限制电影福利在线观看,23伊人大香蕉 百度 好搜 搜狗
        <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <文本链> <文本链> <文本链> <文本链> <文本链> <文本链>