2016-05-25 3 views
2

Таким образом, у меня есть API-интерфейс, не поддерживающий потоки (некоторое программное обеспечение поставщика), которое я сейчас использую, и способ, которым мы в настоящее время используем его, - это один объект на поток. то есть каждая нить имеет:ThreadLocal и non-thread safe 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 на самом деле вынуждает статические области класса существенно нестационарными?

+4

no, ThreadLocal не является статическими областями класса по существу не статическими –

+1

Почему, по вашему мнению, 'ThreadLocal' будет действовать по-разному с локальным объектом в каждом потоке? –

+0

@StrangerintheQ - Ну, ладно, я полагаю, что это отвечает на мой вопрос – eerongal

ответ

5

Все ThreadLocal действительно создает поиск, где каждый поток может найти свой собственный экземпляр объекта, так что ни один поток не должен делиться. Концептуально вы можете думать об этом как о карте с ключом потока.

Позволяя каждой теме использовать свои собственные объекты, это хорошая стратегия для некоторых случаев, она называется «ограничение потока» в книге JCIP. Общим примером этого является то, что объекты SimpleDateFormat не были спроектированы так, чтобы быть потокобезопасными и параллельными потоками, используя их сгенерированные плохие результаты. Использование ThreadLocal позволяет каждому потоку использовать свой собственный DateFormat, see this question for an example.

Но если ваша проблема в том, что объект ссылается на статические поля, то эти статические поля существуют в классе, а не в экземпляре, поэтому использование ThreadLocal не делает ничего для уменьшения общего доступа.

Если бы какой-то из ваших потоков использовал свой собственный загрузчик классов, то каждый из них имел бы свой собственный класс, а статические поля на нем не были бы разделены. В противном случае ваша блокировка в классе кажется разумной (хотя, вероятно, не так быстро, учитывая, что все ваши потоки будут бороться за одну и ту же блокировку). Лучшим подходом будет работа с продавцом, чтобы заставить их исправить свой сломанный код.

+0

Имеет смысл. Спасибо за вход! И да, я изучал это, потому что блокировка не обязательно быстрая, поэтому я надеялся, что, возможно, это поможет в этом отделе. – eerongal

+1

даже статическая блокировка не гарантирует правильность работы. в зависимости от того, какая информация отслеживается через статические переменные, вы все равно можете получить информацию о потоках между вашими потоками. – jtahlborn

+0

@jtahlborn: право, блокировка детализации, возможно, должна быть настолько широкой, что делает многопоточность бессмысленной. я бы исследовал пользовательский угол загрузчика классов. –

1

ThreadLocal не решит вашу проблему, ThreadLocal просто сохраните отдельный экземпляр для каждой темы независимо. так что в вашем случае, если у вас есть общий ресурс на уровне вашей библиотеки rd, который не решит проблему.

Простой синхронизированный монитор позволит решить эту проблему, так как вы хотите, чтобы избежать одновременного доступа к этой библиотеке, но знать о производительности штрафа монитора - только один поток может получить доступ к библиотеке одновременно

Вобще:

public class Bar { 
    private static final Object LOCK = new Object(); 

    public void process() { 
     synchronized(LOCK) { 
      Foo instance = new Foo(); 
      instance.myMethod();    
    } 
} 
Смежные вопросы