ThreadLocal和非线程安全的API

时间:2016-05-25 15:04:48

标签: java multithreading static thread-safety thread-local

所以我有一个非线程安全的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版本是否实际上强制类的静态区域基本上是非静态的?

2 个答案:

答案 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();            
    }
}