這個方案的技術實質是利用java類初始化的lc鎖。相比其他實作方案(如double-checked locking等),該技術方案的實作代碼較為簡潔,并且在所有版本的編譯器中都是可行的。該方案代碼如下:
<code>1</code>
<code>public</code> <code>class</code> <code>instancefactory {</code>
<code>2</code>
<code> </code><code>private</code> <code>static</code> <code>class</code> <code>instanceholder {</code>
<code>3</code>
<code> </code><code>public</code> <code>static</code> <code>instance instance = </code><code>new</code><code>instance();</code>
<code>4</code>
<code> </code><code>}</code>
<code>5</code>
<code>6</code>
<code> </code><code>public</code> <code>static</code> <code>instance getinstance() {</code>
<code>7</code>
<code> </code><code>return</code> <code>instanceholder.instance ; </code><code>//這裡将導緻instanceholder類被初始化</code>
<code>8</code>
<code>9</code>
<code>}</code>
<code>01</code>
<code>public</code> <code>class</code> <code>something {</code>
<code>02</code>
<code> </code><code>private</code> <code>something() {}</code>
<code>03</code>
<code>04</code>
<code> </code><code>private</code> <code>static</code> <code>class</code> <code>lazyholder {</code>
<code>05</code>
<code> </code><code>private</code> <code>static</code> <code>final</code> <code>something instance = </code><code>new</code> <code>something();</code>
<code>06</code>
<code>07</code>
<code>08</code>
<code> </code><code>public</code> <code>static</code> <code>something getinstance() {</code>
<code>09</code>
<code> </code><code>return</code> <code>lazyholder.instance;</code>
<code>10</code>
<code>11</code>
<code>public</code> <code>class</code> <code>singleton {</code>
<code> </code><code>// private constructor prevents instantiation from other classes</code>
<code> </code><code>private</code> <code>singleton() { }</code>
<code> </code><code>/**</code>
<code> </code><code>* singletonholder is loaded on the first execution of singleton.getinstance()</code>
<code> </code><code>* or the first access to singletonholder.instance, not before.</code>
<code> </code><code>*/</code>
<code> </code><code>private</code> <code>static</code> <code>class</code> <code>singletonholder {</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>singleton instance = </code><code>new</code> <code>singleton();</code>
<code>12</code>
<code>13</code>
<code> </code><code>public</code> <code>static</code> <code>singleton getinstance() {</code>
<code>14</code>
<code> </code><code>return</code> <code>singletonholder.instance;</code>
<code>15</code>
<code>16</code>
在讨論這個問題前,首先我們需要明确的是,上述三種方案都是可以保證線程安全的。
t is a class and an instance of t is created. t is a class and a static method declared by t is invoked. a static field declared by t is assigned. a static field declared by t is used and the field is not a constant variable (§4.12.4). t is a top level class (§7.6), and an assert statement (§14.10) lexically nested within t (§8.1.3) is executed.
隻有基本類型或者是string類型的變量,才可能成為constant variable。
回到剛才的問題,在stackoverflow上有相關問題的回答。
首先,關于final關鍵字:
<a href="http://stackoverflow.com/questions/20995036/is-initialization-on-demand-holder-idiom-thread-safe-without-a-final-modifier">http://stackoverflow.com/questions/20995036/is-initialization-on-demand-holder-idiom-thread-safe-without-a-final-modifier</a>
根據該問題的兩個回答,不論有無final關鍵字,事實上都可以保證線程安全,final關鍵的作用僅在于防止對instance做修改。
然後是關于instance的通路權限問題:
<a href="http://stackoverflow.com/questions/21604243/correct-implementation-of-initialization-on-demand-holder-idiom">http://stackoverflow.com/questions/21604243/correct-implementation-of-initialization-on-demand-holder-idiom</a>
這裡提出的觀點是建議如下形式的實作:
<code> </code><code>...</code>
<code> </code><code>static</code> <code>final</code> <code>singleton instance = </code><code>new</code> <code>singleton();</code>
即并不在instance變量前添加public或者private修飾,即使用預設的package private通路權限。
不用public的原因是這個修飾不夠合理,作者認為事實上在lazyholder是被限定為private的情況下,使用public來修飾instance并沒有問題,然而如果有人修改lazyholder為public,那麼就可能出現問題。
otherwise, if the member or constructor is declared private, then access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor.
是以外部類擁有對内部類中private字段的通路權限,那麼在這個情況下,編譯器就會有一些小技巧來保證外部類對内部類private字段的通路權限,即在内部類中插入packge private method,使得外部類調用這些getter和setter方法的形式來通路内部類的private字段。
綜上所述,從線程安全的角度而言,上述的幾種“initialization on demand holder idiom”實作都是沒有問題的。如果讨論細節上的合理性,那麼更推薦最後一種實作,即:
<a href="http://ifeve.com/initialization-on-demand-holder-idiom/#viewsource">檢視源代碼</a>