一個對象如果在建立後不能被修改,那麼就稱為不可變對象。在并發程式設計中,一種被普遍認可的原則就是:盡可能的使用不可變對象來建立簡單、可靠的代碼。
在并發程式設計中,不可變對象特别有用。由于建立後不能被修改,是以不會出現由于線程幹擾産生的錯誤或是記憶體一緻性錯誤。
但是程式員們通常并不熱衷于使用不可變對象,因為他們擔心每次建立新對象的開銷。實際上這種開銷常常被過分高估,而且使用不可變對象所帶來的一些效率提升也抵消了這種開銷。例如:使用不可變對象降低了垃圾回收所産生的額外開銷,也減少了用來確定使用可變對象不出現并發錯誤的一些額外代碼。
接下來看一個可變對象的類,然後轉化為一個不可變對象的類。通過這個例子說明轉化的原則以及使用不可變對象的好處。

<code>01</code>
<code>public</code> <code>class</code> <code>synchronizedrgb {</code>
<code>02</code>
<code>03</code>
<code> </code><code>// values must be between 0 and 255.</code>
<code>04</code>
<code> </code><code>private</code> <code>int</code> <code>red;</code>
<code>05</code>
<code> </code><code>private</code> <code>int</code> <code>green;</code>
<code>06</code>
<code> </code><code>private</code> <code>int</code> <code>blue;</code>
<code>07</code>
<code> </code><code>private</code> <code>string name;</code>
<code>08</code>
<code>09</code>
<code> </code><code>private</code> <code>void</code> <code>check(</code><code>int</code> <code>red,</code>
<code>10</code>
<code> </code><code>int</code> <code>green,</code>
<code>11</code>
<code> </code><code>int</code> <code>blue) {</code>
<code>12</code>
<code> </code><code>if</code> <code>(red < </code><code>0</code> <code>|| red > </code><code>255</code>
<code>13</code>
<code> </code><code>|| green < </code><code>0</code> <code>|| green > </code><code>255</code>
<code>14</code>
<code> </code><code>|| blue < </code><code>0</code> <code>|| blue > </code><code>255</code><code>) {</code>
<code>15</code>
<code> </code><code>throw</code> <code>new</code> <code>illegalargumentexception();</code>
<code>16</code>
<code> </code><code>}</code>
<code>17</code>
<code> </code><code>}</code>
<code>18</code>
<code>19</code>
<code> </code><code>public</code> <code>synchronizedrgb(</code><code>int</code> <code>red,</code>
<code>20</code>
<code> </code><code>int</code> <code>green,</code>
<code>21</code>
<code> </code><code>int</code> <code>blue,</code>
<code>22</code>
<code> </code><code>string name) {</code>
<code>23</code>
<code> </code><code>check(red, green, blue);</code>
<code>24</code>
<code> </code><code>this</code><code>.red = red;</code>
<code>25</code>
<code> </code><code>this</code><code>.green = green;</code>
<code>26</code>
<code> </code><code>this</code><code>.blue = blue;</code>
<code>27</code>
<code> </code><code>this</code><code>.name = name;</code>
<code>28</code>
<code>29</code>
<code>30</code>
<code> </code><code>public</code> <code>void</code> <code>set(</code><code>int</code> <code>red,</code>
<code>31</code>
<code> </code><code>int</code> <code>green,</code>
<code>32</code>
<code> </code><code>int</code> <code>blue,</code>
<code>33</code>
<code> </code><code>string name) {</code>
<code>34</code>
<code>35</code>
<code> </code><code>synchronized</code> <code>(</code><code>this</code><code>) {</code>
<code>36</code>
<code> </code><code>this</code><code>.red = red;</code>
<code>37</code>
<code> </code><code>this</code><code>.green = green;</code>
<code>38</code>
<code> </code><code>this</code><code>.blue = blue;</code>
<code>39</code>
<code> </code><code>this</code><code>.name = name;</code>
<code>40</code>
<code>41</code>
<code>42</code>
<code>43</code>
<code> </code><code>public</code> <code>synchronized</code> <code>int</code> <code>getrgb() {</code>
<code>44</code>
<code> </code><code>return</code> <code>((red << </code><code>16</code><code>) | (green << </code><code>8</code><code>) | blue);</code>
<code>45</code>
<code>46</code>
<code>47</code>
<code> </code><code>public</code> <code>synchronized</code> <code>string getname() {</code>
<code>48</code>
<code> </code><code>return</code> <code>name;</code>
<code>49</code>
<code>50</code>
<code>51</code>
<code> </code><code>public</code> <code>synchronized</code> <code>void</code> <code>invert() {</code>
<code>52</code>
<code> </code><code>red = </code><code>255</code> <code>- red;</code>
<code>53</code>
<code> </code><code>green = </code><code>255</code> <code>- green;</code>
<code>54</code>
<code> </code><code>blue = </code><code>255</code> <code>- blue;</code>
<code>55</code>
<code> </code><code>name = </code><code>"inverse of "</code> <code>+ name;</code>
<code>56</code>
<code>57</code>
<code>}</code>
使用synchronizedrgb時需要小心,避免其處于不一緻的狀态。例如一個線程執行了以下代碼:
<code>1</code>
<code>synchronizedrgb color =</code>
<code>2</code>
<code> </code><code>new</code> <code>synchronizedrgb(</code><code>0</code><code>, </code><code>0</code><code>, </code><code>0</code><code>, </code><code>"pitch black"</code><code>);</code>
<code>3</code>
<code>...</code>
<code>4</code>
<code>int</code> <code>mycolorint = color.getrgb(); </code><code>//statement 1</code>
<code>5</code>
<code>string mycolorname = color.getname(); </code><code>//statement 2</code>
如果有另外一個線程在statement 1之後、statement 2之前調用了color.set方法,那麼mycolorint的值和mycolorname的值就會不比對。為了避免出現這樣的結果,必須要像下面這樣把這兩條語句綁定到一塊執行:
<code>synchronized</code> <code>(color) {</code>
<code> </code><code>int</code> <code>mycolorint = color.getrgb();</code>
<code> </code><code>string mycolorname = color.getname();</code>
這種不一緻的問題隻可能發生在可變對象上。
以下的一些規則是建立不可變對象的簡單政策。并非所有不可變類都完全遵守這些規則,不過這不是編寫這些類的程式員們粗心大意造成的,很可能的是他們有充分的理由確定這些對象在建立後不會被修改。但這需要非常複雜細緻的分析,并不适用于初學者。

不要提供setter方法。(包括修改字段的方法和修改字段引用對象的方法)
将類的所有字段定義為final、private的。
不允許子類重寫方法。簡單的辦法是将類聲明為final,更好的方法是将構造函數聲明為私有的,通過工廠方法建立對象。
如果類的字段是對可變對象的引用,不允許修改被引用對象。
不提供修改可變對象的方法。
不共享可變對象的引用。當一個引用被當做參數傳遞給構造函數,而這個引用指向的是一個外部的可變對象時,一定不要儲存這個引用。如果必須要儲存,那麼建立可變對象的拷貝,然後儲存拷貝對象的引用。同樣如果需要傳回内部的可變對象時,不要傳回可變對象本身,而是傳回其拷貝。
将這一政策應用到synchronizedrgb有以下幾步:
synchronizedrgb類有兩個setter方法。第一個set方法隻是簡單的為字段設值(譯者注:删掉即可),第二個invert方法修改為建立一個新對象,而不是在原有對象上修改。
所有的字段都已經是私有的,加上final即可。
将類聲明為final的
隻有一個字段是對象引用,并且被引用的對象也是不可變對象。
<a href="http://ifeve.com/immutable-objects/#viewsource">檢視源代碼</a>
<code>final</code> <code>public</code> <code>class</code> <code>immutablergb {</code>
<code> </code><code>final</code> <code>private</code> <code>int</code> <code>red;</code>
<code> </code><code>final</code> <code>private</code> <code>int</code> <code>green;</code>
<code> </code><code>final</code> <code>private</code> <code>int</code> <code>blue;</code>
<code> </code><code>final</code> <code>private</code> <code>string name;</code>
<code> </code><code>public</code> <code>immutablergb(</code><code>int</code> <code>red,</code>
<code> </code><code>int</code> <code>green,</code>
<code> </code><code>int</code> <code>blue,</code>
<code> </code><code>string name) {</code>
<code> </code><code>public</code> <code>int</code> <code>getrgb() {</code>
<code> </code><code>public</code> <code>string getname() {</code>
<code> </code><code>public</code> <code>immutablergb invert() {</code>
<code> </code><code>return</code> <code>new</code> <code>immutablergb(</code><code>255</code> <code>- red,</code>
<code> </code><code>255</code> <code>- green,</code>
<code> </code><code>255</code> <code>- blue,</code>
<code> </code><code>"inverse of "</code> <code>+ name);</code>