-
(1) 訪問共享的可變數(shù)據(jù)時, 通常就需要同步
(2) 為了避免同步, 可以不共享數(shù)據(jù), 在單線程內(nèi)訪問拘束的話就不需要共享數(shù)據(jù), 這就叫線程封閉
-
線程封閉的方式
(1) Ad-hoc封閉: 完全交給程序?qū)崿F(xiàn)者承擔
盡量少用這種方式
(2) 棧封閉: 只能通過局部變量訪問對象
示例
public class Animals { ... public int loadTheArk(Collection<Animal> candidates) { SortedSet<Animal> animals; int numPairs = 0; Animal candidate = null; // animals confined to method, don't let them escape! animals = new TreeSet<Animal>(new SpeciesGenderComparator()); 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; } }這個示例中, 輸入?yún)?shù) candidates 是共享的數(shù)據(jù), 而棧封閉的意思是訪問對象只能通過局部變量, 因此示例中使用局部變量animals作為candidates的副本,所有的訪問都發(fā)生在局部變量animals上, 這樣根本就不會共享數(shù)據(jù)。
使用棧封閉的風(fēng)險是: 需求必須明確, 否則很有可能被后續(xù)的維護人員錯誤將對象逸出(例如示例中將candidates或者animals傳到了其他線程中)
(2) 使用ThreadLocal類
1° JavaDoc說明
This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its {@code get} or {@code set} method) has its own, independently initialized copy of the variable. {@code ThreadLocal} instances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID).
For example, the class below generates unique identifiers local to each thread. A thread's id is assigned the first time it invokes {@code ThreadId.get()} and remains unchanged on subsequent calls.
class ThreadId { // Atomic integer containing the next thread ID to be assigned private static final AtomicInteger nextId = new AtomicInteger(0); // Thread local variable containing each thread's ID private static final ThreadLocal<Integer> threadId = new ThreadLocal<Integer>() { @Override protected Integer initialValue() { return nextId.getAndIncrement(); } }; // Returns the current thread's unique ID, assigning it if necessary public static int get() { return threadId.get(); } }Each thread holds an implicit reference to its copy of a thread-local variable as long as the thread is alive and the {@code ThreadLocal} instance is accessible; after a thread goes away, all of its copies of thread-local instances are subject to garbage collection (unless other references to these copies exist).
2° 從概念上看, ThreadLocal<T>相當于內(nèi)置了Map<Thread, T>, 其中保存了特定于當前線程的值
3° 如果需要將一個單線程應(yīng)用程序移植到多線程環(huán)境中,可以將共享的變量轉(zhuǎn)換為ThreadLocal對象
4° 示例
public class ConnectionDispenser { static String DB_URL = "jdbc:mysql://localhost/mydatabase"; private ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() { @Override protected Connection initialValue() { try { return DriverManager.getConnection(DB_URL); } catch (SQLException e) { throw new RuntimeException("Unable to acquire Connection, e"); } } }; public Connection getConnection() { return connectionHolder.get(); } }這樣, 每個線程都會擁有屬于自己的Connection對象副本, 它們互不干擾
1_基礎(chǔ)知識_chapter03_對象的共享_3_線程封閉
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
相關(guān)閱讀更多精彩內(nèi)容
- 最近,網(wǎng)絡(luò)上關(guān)于“中年危機”的話題很火。不僅是70后、80后,連90后都開始自嘲,感覺到中年危機,喝杯白開水都想加...