所以我有一个非线程安全的API(某些供应商软件)我正在使用,而我们当前使用它的方式是每个线程一个对象。即每个帖子都有:
Foo instance = new Foo();
但是,这似乎不适用于此特定库。它的一些非线程安全位仍然看起来像是头,所以我假设这个库中有一些静态值。在我们知道它有问题的几个点上,我们目前正在使用ReentrantLock在需要时锁定该类。即。
public class Bar {
protected static final ReentrantLock lock = new ReentrantLock();
public void process() {
Foo instance = new Foo();
boolean locked = false;
try{
if(SomeCondition) {
locked = true;
Bar.lock.lock();
}
*//rest of the processing goes here
} finally {
if(locked){
Bar.lock.unlock();
}
}
}
}
我的问题是:在这样一个实例中,所讨论的类不是线程安全的,即使在创建所述类的新实例时,使用锁定是否更好,或者我应该看看我是否正在使用ThreadLocals? ThreadLocals会减轻我的实际问题吗?类的ThreadLocal版本是否实际上强制类的静态区域基本上是非静态的?
答案 0 :(得分:5)
所有ThreadLocal都会创建一个查找,其中每个线程都可以找到自己的对象实例,因此没有线程必须共享。从概念上讲,您可以将其视为由线程ID键入的地图。
让每个线程使用自己的对象对于某些情况来说是一个很好的策略,它在JCIP书中被称为“线程限制”。一个常见的例子是SimpleDateFormat对象不是设计为线程安全的,并且使用它们的并发线程产生了错误的结果。使用ThreadLocal允许每个线程使用自己的DateFormat see this question for an example。
但是如果您的问题是对象引用了静态字段,那么这些静态字段存在于类中,而不存在于实例上,因此使用ThreadLocal不会做任何事情来减少共享。
如果你的每个线程都以某种方式使用自己的类加载器,那么每个线程都有自己的类,并且不会共享其上的静态字段。否则你对类的锁定似乎是合理的(尽管考虑到所有的线程都会争用同一个锁,但可能并不快)。 最好的方法是与供应商合作,让他们修复破损的代码。
答案 1 :(得分:1)
ThreadLocal
无法解决您的问题,ThreadLocal
只是为每个线程独立存储不同的实例。所以在您的情况下,如果您在3 rd 方库级别上共享资源,则无法解决问题。
一个简单的同步监视器将解决这个问题,因为你想避免对该库的并发访问,但要注意监视器的性能损失 - 只有一个线程可以同时访问lib
只是做:
public class Bar {
private static final Object LOCK = new Object();
public void process() {
synchronized(LOCK) {
Foo instance = new Foo();
instance.myMethod();
}
}