一、不要在構造過程當中使this引用逸出。當且僅當對象的構造函數返回時,對象才處於可預測和一致的狀態,當從對象的構造函數中發佈對象時,只是發佈了一個還沒有構造完成的對象。只有當構造函數返回時,this引用才應該從線程中逸出,構造函數能夠將this引用保存到某個地方,只要其餘線程不會在構造函數以前使用它。若是想在構造函數中註冊事件監聽器或者啓動線程,能夠使用一個私有的構造函數和公共的工廠方法。緩存
public class SafeListener { private final EventListener listener; private SafeListener(){ listener = new EventListener(){ public void onEvent(Event e){ //TODO } }; } public static SafeListener newInstance(EventSource source){ SafeListener safe = new SafeListener(); source.registerListener(safe.listener); return safe; } }
二、線程封閉(Thread Confinement),JDBC中的Connection對象就使用了線程封閉技術。JDBC規範並不要求Connection是線程安全的,可是鏈接池將其分配給一個線程以後,到Connection返回給鏈接池以前,鏈接池不會再把該Connection分配給其餘線程使用,所以至關於線程封閉了;ThreadLocal也是線程封閉的。 AD HOC線程封閉,不多用(未懂是什麼)。 棧封閉:只能經過局部變量才能訪問對象(局部變量被封閉在執行線程中,所以天然的封閉了)。書中的例子:安全
public int loadTheArk(Collection<Animal> candidates){ SortedSet<Animal> animals; int numPairs = 0; Animal candidate = 0; //animals封閉在方法中,不要使其逸出 animals = new TreeSet<Animal>(new SpecialGenderComparator()); animals.addAll(candidates); for(Animal a : animals){ if(candidate == null || !candidate.isPotentialMate(a)) candidate = a; else{ ark.load(new AnimalPair(candidate,a)); ++numPairs; candidate = null; } } return numPairs; }
線程封閉性更規範的方法:ThreadLocal,防止可變的單實例變量(Singleton)或全局變量進行共享。框架
private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>(){ public Connection initialValue(){ Connection conn = null; try { conn = DriverManager.getConnection("URL"); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return conn; } }; public static Connection getConnection(){ return connectionHolder.get(); }
能夠用來保存事務上下文,避免調用每一個方法時都要傳遞執行上下文信息。這樣也會使運用了該機制的框架代碼與通常代碼耦合在一塊兒。濫用ThreadLocal相似於全局變量,下降代碼可重用性,並在類之間引入隱含的耦合性。函數
三、不變性:不可變對象必定是線程安全的,全部的域都是final類型的,對象也未必是不可變的,由於final類型的域能夠保存可變對象的引用。符合如下條件則不可變: .)對象建立之後其狀態就不能修改; .)對象的全部域都是final類型; .)對象都是正確建立的(在對象建立期間,this引用沒有逸出)。 「不可變的對象」與「不可變的對象引用」之間存在差別,保存在不可變對象中的程序狀態依然能夠更新,可經過一個保存新狀態的實例來替換原有的不可變對象。 大神們說的良好變成習慣:除非須要更高的可見性,不然將全部的域都聲明爲私有域;除非須要某個域是可變的,不然應將其聲明爲final域。 能夠使用指向不可變容器對象的volatile類型引用以緩存最新的結果。this
4安全發佈:安全發佈一個對象,對象引用和對象狀態必須同時對其餘線程可見,一個正確構造的對象能夠經過如下方式安全發佈: .)在靜態初始化函數中初始化一個對象引用; .)將對象的引用保存到volatile類型的域或者AtomicReferance對象中; .)將對象的引用保存到某個正確構造對象的final類型域中。 .)將對象的引用保存到一個由鎖保護的域中。線程