posts - 495,  comments - 11,  trackbacks - 0

          1,保證線程安全的三種方法:
          ??? a,不要跨線程訪問共享變量

          ??? b,使共享變量是
          final類型的
          ??? c,將共享變量的操作加上同步


          2,一開始就將類設(shè)計成線程安全的
          ,比在后期重新修復(fù)它,更容易.

          3,編寫多線程程序
          ,首先保證它是正確的,其次再考慮性能
          .

          4,無狀態(tài)或只讀對象永遠是線程安全的
          .

          5,不要將一個共享變量裸露在多線程環(huán)境下
          (無同步或不可變性保護
          )

          6,多線程環(huán)境下的延遲加載需要同步的保護
          ,因為延遲加載會造成對象重復(fù)實例化


          7,對于
          volatile 聲明的數(shù)值類型變量進行運算,往往是不安全的(volatile 只能保證可見性, 不能保證原子性).
          詳見
          volatile 原理與技巧中,臟數(shù)據(jù)問題討論
          .

          8,當(dāng)一個線程請求獲得它自己占有的鎖時
          ( 同一把鎖的嵌套使用),我們稱該鎖為可重入鎖.
          jdk1.5 并發(fā)包中,提供了可重入鎖的java 實現(xiàn)
          -ReentrantLock.

          9,每個共享變量
          , 都應(yīng)該由一個唯一確定的鎖保護.
          創(chuàng)建與變量相同數(shù)目的
          ReentrantLock,使他們負責(zé)每個變量的線程安全
          .

          10,雖然縮小同步塊的范圍
          ,可以提升系統(tǒng)性能.
          但在保證原子性的情況下
          ,不可將原子操作分解成多個synchronized
          .

          11,在沒有同步的情況下
          ,編譯器與處理器運行時的指令執(zhí)行順序可能完全出乎意料
          .
          原因是
          ,編譯器或處理器為了優(yōu)化自身執(zhí)行效率,而對指令進行了的重排序
          (reordering).

          12,當(dāng)一個線程在沒有同步的情況下讀取變量
          ,它可能會得到一個過期值,但是至少它可以看到那個

          線程在當(dāng)時設(shè)定的一個真實數(shù)值
          .而不是憑空而來的值.這種安全保證,稱之為最低限的安全性(out-of-thin-air safety)

          在開發(fā)并發(fā)應(yīng)用程序時
          ,有時為了大幅度提高系統(tǒng)的吞吐量與性能,會采用這種無保障的做法
          .
          但是針對
          ,數(shù)值的運算,仍舊是被否決的
          .

          13,volatile 變量
          , 只能保證可見性,無法保證原子性
          .

          14,某些耗時較長的網(wǎng)絡(luò)操作或IO,確保執(zhí)行時,不要占有鎖.

          15,發(fā)布(publish) 對象,指的是使它能夠被當(dāng)前范圍之外的代碼所使用.( 引用傳遞
          )
          對象逸出(escape),指的是一個對象在尚未準備好時將它發(fā)布.

          原則:為防止逸出,對象必須要被完全構(gòu)造完后,才可以被發(fā)布( 最好的解決方式是采用同步
          )

          this
          關(guān)鍵字引用對象逸出

          例子:在構(gòu)造函數(shù)中,開啟線程,并將自身對象this 傳入線程,造成引用傳遞.
          而此時,構(gòu)造函數(shù)尚未執(zhí)行完,就會發(fā)生對象逸出了
          .

          16,必要時,使用ThreadLocal變量確保線程封閉性(封閉線程往往是比較安全的,但一定程度上會造成性能損耗)
          封閉對象的例子在實際使用過程中,比較常見,例如hibernate openSessionInView機制, jdbcconnection機制.

          17,單一不可變對象往往是線程安全的(復(fù)雜不可變對象需要保證其內(nèi)部成員變量也是不可變的)
          良好的多線程編程習(xí)慣是:將所有的域都聲明為final,除非它們是可變的

          18,保證共享變量的發(fā)布是安全的

          ??? a,
          通過靜態(tài)初始化器初始化對象(jls 12.4.2 敘述, jvm 會保證靜態(tài)初始化變量是同步的)
          ??? b,
          將對象申明為volatile 或使用
          AtomicReference
          ??? c,
          保證對象是不可變的

          ??? d,
          將引用或可變操作都由鎖來保護

          19,設(shè)計線程安全的類,應(yīng)該包括的基本要素:
          ??? a,確定哪些是可變共享變量
          ??? b,確定哪些是不可變的變量
          ??? c,指定一個管理并發(fā)訪問對象狀態(tài)的策略

          20,將數(shù)據(jù)封裝在對象內(nèi)部,并保證對數(shù)據(jù)的訪問是原子的
          .
          建議采用volatile javabean 模型或者構(gòu)造同步的getter,setter.

          21,線程限制性使構(gòu)造線程安全的類變得更容易,因為類的狀態(tài)被限制后,分析它的線程安全性時,就不必檢查完整的程序.

          22,
          編寫并發(fā)程序,需要更全的注釋,更完整的文檔說明.

          23,在需要細分鎖的分配時,使用java監(jiān)視器模式好于使用自身對象的監(jiān)視器鎖.
          前者的靈活性更好.

          Object target = new Object();
          //這里使用外部對象來作為監(jiān)視器,而非this
          synchronized(target) {
          ??? // TODO
          }

          針對java monitor pattern,實際上ReentrantLock的實現(xiàn)更易于并發(fā)編程.
          功能上,也更強大.

          24,設(shè)計并發(fā)程序時,在保證伸縮性與性能折中的前提下,優(yōu)先考慮將共享變量委托給線程安全的類
          .
          由它來控制全局的并發(fā)訪問
          .

          25,使用普通同步容器(Vector, Hashtable) 的迭代器,需要外部鎖來保證其原子性
          .
          原因是,普通同步容器產(chǎn)生的迭代器是非線程安全的
          .

          26,在并發(fā)編程中,需要容器支持的時候,優(yōu)先考慮使用jdk 并發(fā)容器

          (ConcurrentHashMap, ConcurrentLinkedQueue, CopyOnWriteArrayList...).


          27, ConcurrentHashMap, CopyOnWriteArrayList

          并發(fā)容器的迭代器, 以及全范圍的size(), isEmpty()都表現(xiàn)出弱一致性
          .
          他們只能標(biāo)示容器當(dāng)時的一個數(shù)據(jù)狀態(tài).無法完整響應(yīng)容器之后的變化和修改
          .

          28,
          使用有界隊列,在隊列充滿或為空時,阻塞所有的讀與寫操作. ( 實現(xiàn)生產(chǎn)- 消費的良好方案)

          BlockQueue
          下的實現(xiàn)有LinkedBlockingQueue ArrayBlockingQueue,前者為鏈表,可變操作頻繁優(yōu)先考慮, 后者為數(shù)組,讀取操作頻繁優(yōu)先考慮.
          PriorityBlockingQueue
          是一個按優(yōu)先級順序排列的阻塞隊列,它可以對所有置入的元素進行排序( 實現(xiàn)Comparator 接口
          )

          29,
          當(dāng)一個方法,能拋出InterruptedException,則意味著,這個方法是一個可阻塞的方法,如果它被中斷,將提前結(jié)束阻塞狀態(tài)
          .
          當(dāng)你調(diào)用一個阻塞方法,也就意味著,本身也稱為了一個阻塞方法,因為你必須等待阻塞方法返回
          .

          如果阻塞方法拋出了中斷異常,我們需要做的是,將其往上層拋,除非當(dāng)前已經(jīng)是需要捕獲異常的層次
          .
          如果當(dāng)前方法,不能拋出InterruptedException,可以使用Thread.currentThread.interrupt() 方法,手動進行中斷.

          ?

          posted on 2011-05-18 22:53 jadmin 閱讀(166) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 静安区| 汝州市| 郁南县| 介休市| 平安县| 德阳市| 南皮县| 桃江县| 石林| 紫云| 奎屯市| 桐梓县| 泸水县| 武陟县| 宣城市| 和龙市| 大悟县| 乡宁县| 澳门| 白河县| 涞源县| 沁水县| 北海市| 新民市| 连平县| 崇礼县| 微山县| 贵定县| 成武县| 察隅县| 河间市| 高唐县| 岳阳市| 贵州省| 类乌齐县| 大庆市| 乌海市| 五寨县| 务川| 贵德县| 渝北区|