dingfirst

          On the Road

            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            8 隨筆 :: 2 文章 :: 3 評(píng)論 :: 0 Trackbacks

          原文名稱(chēng):Double-checked locking and the Singleton pattern

          ???????????????????????????A comprehensive look at this broken programming idiom


          1,請(qǐng)首先看一下下面的這個(gè)類(lèi),只有第一個(gè)getInstance()方法是正確的。其中g(shù)etInstance4()就是由于所謂的"out-of-order"問(wèn)題引起的(詳見(jiàn)注釋?zhuān)?br />getInstance5()則是因?yàn)榫幾g器優(yōu)化導(dǎo)致的。

          package ?org.ding.util;
          import ?java.util. * ;

          public ? class ?Singleton? {
          ????
          ????
          private ? static ?Singleton?instance;
          ????
          private ?Vector?v;
          ????
          private ? boolean ?inUse;


          ????
          private ?Singleton()? {
          ????????v?
          = ? new ?Vector();
          ????????v.addElement(
          new ?Object());
          ????????inUse?
          = ? true ;
          ????}

          ????
          ????
          // ok
          ???? public ? static ? synchronized ?Singleton?getInstance()? {
          ????????
          if ?(instance? == ? null )? // 1
          ????????????instance? = ? new ?Singleton();? // 2
          ???????? return ?instance;? // 3
          ????}


          ????
          ????
          // error
          ???? public ? static ?Singleton?getInstance2()? {
          ????????
          if ?(instance? == ? null )? // 1
          ????????????instance? = ? new ?Singleton();? // 2?,此處競(jìng)爭(zhēng)
          ???????? return ?instance;? // 3
          ????}

          ????
          ????
          // error
          ???? public ? static ?Singleton?getInstance3()? {
          ????????
          if ?(instance? == ? null )? {
          ????????????
          synchronized ?(Singleton. class )? {?? // 此處競(jìng)爭(zhēng)
          ????????????????instance? = ? new ?Singleton();
          ????????????}

          ????????}

          ????????
          return ?instance;
          ????}


          ????
          /*
          ?????*error
          ?????*known?as?double-checke
          ?????*
          ?????*The?issue?of?the?failure?of?double-checked?locking?is?not?due?to?implementation?bugs?in?JVMs?
          ?????*but?to?the?current?Java?platform?memory?model.?
          ?????*The?memory?model?allows?what?is?known?as?"out-of-order?writes"?and?is?a?prime?reason?why?this?idiom?fails.
          ?????*
          ?????*看一下代碼的//3處是如何執(zhí)行的:
          ?????*???????mem?=?allocate();?????????????//a,Allocate?memory?for?Singleton?object.
          ?????*???????instance?=?mem;???????????????//b,Note?that?instance?is?now?non-null,?but?has?not?been?initialized.
          ?????*???????ctorSingleton(instance);??????//c,Invoke?constructor?for?Singleton?passing?instance.
          ????
          */

          ????
          public ? static ?Singleton?getInstance4()? {
          ????????
          if ?(instance? == ? null )? {? // 1
          ???????????? synchronized ?(Singleton. class )? {? // 2
          ???????????????? if ?(instance? == ? null )? // 3
          ????????????????????instance? = ? new ?Singleton();? // 3,此處線(xiàn)1程如果執(zhí)行完b,但還沒(méi)有執(zhí)行c的時(shí)候,線(xiàn)程2執(zhí)行 // 1,會(huì)返回未完全初始化的對(duì)象
          ????????????}

          ????????}

          ????????
          return ?instance;
          ????}

          ????
          ????
          // error
          ????
          // 這個(gè)的問(wèn)題在于:
          ????
          // The?Java?Language?Specification?(JLS)?demands?that?code?within?a?synchronized?block?not?be?moved?out?of?a?synchronized?block.?
          ????
          // However,?it?does?not?say?that?code?not?in?a?synchronized?block?cannot?be?moved?into?a?synchronized?block.

          ????
          /**
          ?????*?getInstance5??error
          ?????*
          ?????*?這個(gè)方法失敗的問(wèn)題在于:
          ?????*?The?Java?Language?Specification?(JLS)?demands?that?code?within?a?synchronized?block?not?be?moved?out?of?a?synchronized?block.?
          ?????*?However,?it?does?not?say?that?code?not?in?a?synchronized?block?cannot?be?moved?into?a?synchronized?block.
          ?????*?
          ?????*?所以//3至//5之間的代碼會(huì)被編譯器優(yōu)化為:
          ?????*???????if?(inst?==?null)?{
          ?????*????????????synchronized?(Singleton.class)?{?//3
          ?????*???????????????instance?=?new?Singleton();???????????????
          ?????*?????????????}
          ?????*????????}
          ?????*
          ?????*?
          @return ?Singleton
          ?????
          */

          ????
          public ? static ?Singleton?getInstance5()? {
          ????????
          if ?(instance? == ? null )? {
          ????????????
          synchronized ?(Singleton. class )? {? // 1
          ????????????????Singleton?inst? = ?instance;? // 2
          ???????????????? if ?(inst? == ? null )? {
          ????????????????????
          synchronized ?(Singleton. class )? {? // 3
          ????????????????????????inst? = ? new ?Singleton();? // 4
          ????????????????????}

          ????????????????????instance?
          = ?inst;? // 5
          ????????????????}

          ????????????}

          ????????}

          ????????
          return ?instance;
          ????}

          }

          2,還有一種正確的方式
          class?Singleton2?{
          ????
          private?Vector?v;
          ????
          private?boolean?inUse;
          ????
          private?static?Singleton2?instance?=?new?Singleton2();

          ????
          private?Singleton2()?{
          ????????v?
          =?new?Vector();
          ????????inUse?
          =?true;
          ????????
          //
          ????}


          ????
          public?static?Singleton2?getInstance()?{
          ????????
          return?instance;
          ????}

          }

          3,volitile為什么不行?

          Another idea is to use the keyword volatile for the variables inst and instance. According to the JLS (see Resources), variables declared volatile are supposed to be sequentially consistent, and therefore, not reordered. But two problems occur with trying to use volatile to fix the problem with double-checked locking:

          • The problem here is not with sequential consistency. Code is being moved, not reordered.

          • Many JVMs do not implement volatile correctly regarding sequential consistency anyway.

          The second point is worth expanding upon. Consider the code in Listing 9:


          Listing 9. Sequential consistency with volatile
          class test
          {
            private volatile boolean stop = false;
            private volatile int num = 0;
          
            public void foo()
            {
              num = 100;    //This can happen second
              stop = true;  //This can happen first
              //...
            }
          
            public void bar()
            {
              if (stop)
                num += num;  //num can == 0!
            }
            //...
          }
          

          According to the JLS, because stop and num are declared volatile, they should be sequentially consistent. This means that if stop is ever true, num must have been set to 100. However, because many JVMs do not implement the sequential consistency feature of volatile, you cannot count on this behavior. Therefore, if thread 1 called foo and thread 2 called bar concurrently, thread 1 might set stop to true before num is set to 100. This could lead thread 2 to see stop as true, but num still set to 0. There are additional problems with volatile and the atomicity of 64-bit variables, but this is beyond the scope of this article. See Resources for more information on this topic.

          4,String類(lèi)會(huì)有"out-of-order"問(wèn)題么?

          ???答案是比較老的版本會(huì)有:
          ???"Running this code on old JVMs like Sun JDK 1.2.1 results in the out-of-order write problem, and thus, a non-immutable String."
          ???"Both the IBM 1.3 and Sun 1.3 JVMs produce immutable Strings as expected."

          class?StringReader?extends?Thread?{
          ????MutableString?ms;
          ????
          public?StringReader(MutableString?muts)?{
          ????????ms?
          =?muts;
          ????}


          ????
          public?void?run()?{
          ????????
          while?(true)?{
          ????????????
          if?(!(ms.str.equals("hello")))?{?//2
          ????????????????System.out.println("String?is?not?immutable!");//Peter Haggar?說(shuō)此處是由輸出的。
          ????????????????
          break;
          ????????????}

          ????????}

          ????}

          }


          class?MutableString?{
          ????
          public?String?str;?//3
          ????public?static?void?main(String?args[])?{
          ????????MutableString?ms?
          =?new?MutableString();?//4
          ????????new?StringCreator(ms).start();?//5
          ????????new?StringReader(ms).start();?//6
          ????}

          }
          posted on 2006-07-18 19:17 dingfirst 閱讀(333) 評(píng)論(0)  編輯  收藏

          只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 南皮县| 富平县| 清新县| 潼关县| 陆良县| 万年县| 马边| 芜湖市| 威信县| 沙湾县| 区。| 喀喇| 靖州| 织金县| 惠来县| 仪陇县| 泸溪县| 溧阳市| 盱眙县| 乌审旗| 清水县| 泌阳县| 盘锦市| 吴旗县| 芜湖市| 万宁市| 黑山县| 嘉黎县| 天镇县| 都江堰市| 依兰县| 开阳县| 财经| 龙门县| 敦煌市| 哈巴河县| 泰和县| 渑池县| 孟津县| 临颍县| 丹阳市|