ThreadLocal的使用如何降低可重用性

时间:2012-07-01 15:43:54

标签: java multithreading concurrency synchronization thread-local

备受好评的书籍JCIP说明了ThreadLocal的用法:

  

通过将线程限制属性视为使用全局变量的许可证或创建“隐藏”方法参数的方法,很容易滥用ThreadLocal。   线程局部变量会降低可重用性并在类之间引入隐藏的耦合,因此应谨慎使用。

说Thread-local变量可以减少可重用性并在类之间引入隐藏的耦合是什么意思?

2 个答案:

答案 0 :(得分:11)

它们以与全局变量相同的方式减少可重用性:当方法的计算依赖于方法外部的状态,但不作为参数传递(例如类字段)时,您的方法不太可重用,因为它与它所在的对象/类的状态紧密耦合(或者更糟糕的是,完全在另一个类上)。

修改:好的,这是一个让它更清晰的例子。我只是为了问题而使用ThreadLocal,但它一般适用于全局变量。假设我想在几个线程上并行计算前N个整数的总和。我们知道最好的方法是计算每个线程的本地总和,然后在最后总结它们。出于某种原因,我们决定每个call的{​​{1}}方法将使用在不同类中定义的Task变量作为全局(静态)变量:

ThreadLocal sum

代码正常运行并为我们提供了全局和的预期值,但我们注意到类class Foo { public static ThreadLocal<Long> localSum = new ThreadLocal<Long>() { public Long initialValue() { return new Long(0); } }; } class Task implements Callable<Long> { private int start = 0; private int end = 0; public Task(int start, int end) { this.start = start; this.end = end; } public Long call() { for(int i = start; i < end; i++) { Foo.localSum.set(Foo.localSum.get() + i); } return Foo.localSum.get(); } } 及其Task方法现在严格地与call类耦合。如果我想在另一个项目中重用Foo类,我还必须移动Task类,否则代码将无法编译。

虽然这是一个简单的复杂例子,但您可以看到“隐藏”全局变量的危险。它还会影响可读性,因为阅读代码的其他人也必须搜索类Foo并查看Foo的定义。你应该尽可能保持自己的课程。

答案 1 :(得分:3)

每个线程声明一个ThreadLocal - 通常会为该类的每个对象声明一个字段 - 从此开始 - 如果ThreadLocal被滥用,可能会出现很多错误

如果线程通过多个对象(单个类或多个类),则此线程使用的ThreadLocal在所有这些实例中都是相同的实例。这是BG正在谈论的耦合。在存在耦合的那一刻 - 可重用性变得困难且容易出错。