-
(1) 访问共享的可变数据时, 通常就需要同步
(2) 为了避免同步, 可以不共享数据, 在单线程内访问拘束的话就不需要共享数据, 这就叫线程封闭
-
线程封闭的方式
(1) Ad-hoc封闭: 完全交给程序实现者承担
尽量少用这种方式
(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; } }
这个示例中, 输入参数 candidates 是共享的数据, 而栈封闭的意思是访问对象只能通过局部变量, 因此示例中使用局部变量animals作为candidates的副本,所有的访问都发生在局部变量animals上, 这样根本就不会共享数据。
使用栈封闭的风险是: 需求必须明确, 否则很有可能被后续的维护人员错误将对象逸出(例如示例中将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>相当于内置了Map<Thread, T>, 其中保存了特定于当前线程的值
3° 如果需要将一个单线程应用程序移植到多线程环境中,可以将共享的变量转换为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_基础知识_chapter03_对象的共享_3_线程封闭
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- 最近,网络上关于“中年危机”的话题很火。不仅是70后、80后,连90后都开始自嘲,感觉到中年危机,喝杯白开水都想加...