2009-08-23 2 views
3

Я пытаюсь использовать ThreadLocal, чтобы обеспечить безопасность потоков до уже существующих классов, не связанных с потоком, но испытывающих проблемы. Похоже, что не выполняется изоляция - что потоки по-прежнему разделяют статичность, а не локальны для каждого потока.Использование ThreadLocal с существующими классами, которые содержат статические члены

Я считаю, что мое использование почти точно совпадает с примером локализации SimpleDateFormatter, описанным в this StackOverflow question, но это не работает так, как я надеюсь.

Я надеюсь, что кто-то из тех, кто использовал это, укажет на грубую ошибку, которую я должен сделать ... поэтому, я думаю, мой вопрос: можете ли вы определить, что я делаю неправильно здесь?

Вот мой простой класс:

public class SimpleClassWithStaticMembers { 
    private static String theStaticString = 
     "StaticStringInClassWithStaticMember"; 
    public void setTheStaticString (String val) { 
     SimpleClassWithStaticMembers.theStaticString = val; 
    } 
    public String getTheStaticString() { 
     return SimpleClassWithStaticMembers.theStaticString; 
    } 
} 

И это класс нить, которая создает ThreadLocal экземпляры SimpleClassWithStaticMembers:

public class SimpleTesterThread extends Thread { 
    private void showMsg (String msg) { 
     System.out.println (msg); 
     System.out.flush(); 
    } 
    public SimpleTesterThread (String threadId) { 
     super(threadId); 
    } 
    public void run() { 
     try { Thread.sleep(2000); } catch (InterruptedException ex) { } 
     ThreadLocal<SimpleClassWithStaticMembers> localizedClass = 
      new ThreadLocal<SimpleClassWithStaticMembers>(); 
     localizedClass.set(new SimpleClassWithStaticMembers()); 
     // repeating here to be sure we overlap all with all 
     for (int ii=0; ii < 3; ii++) { 
      localizedClass.get().setTheStaticString ("Setby_" + this.getName()); 
      try { Thread.sleep(2000); } catch (InterruptedException ex) { } 
      showMsg("   Thread [" + this.getName() + "] - " 
       + localizedClass.get().getTheStaticString() + "'."); 
     } 
     showMsg ("Thread [" + this.getName() 
      + "] complete. Our 'threadlocal' string is now - " 
      + localizedClass.get().getTheStaticString() + "'."); 
     localizedClass.remove(); 
    } 
} 

Когда десять экземпляров SimpleTesterThread созданы (давая им различные имена потоков, как «AAAAAAAAAA», «BBBBBBBBB» и т. Д.), А затем началось, вывод ясно показывает, что они совместно используют экземпляры. Вход Выход включает в себя:

 
... 
      Thread [JJJJJJJJJJ] - Setby_CCCCCCCCCC'. 
      Thread [DDDDDDDDDD] - Setby_JJJJJJJJJJ'. 
      Thread [IIIIIIIIII] - Setby_DDDDDDDDDD'. 
      Thread [GGGGGGGGGG] - Setby_IIIIIIIIII'. 
      Thread [EEEEEEEEEE] - Setby_GGGGGGGGGG'. 
Thread [EEEEEEEEEE] complete. Our 'threadlocal' string is now - Setby_GGGGGGGGGG'. 
      Thread [HHHHHHHHHH] - Setby_GGGGGGGGGG'. 
      Thread [BBBBBBBBBB] - Setby_GGGGGGGGGG'. 
      Thread [FFFFFFFFFF] - Setby_GGGGGGGGGG'. 
Thread [FFFFFFFFFF] complete. Our 'threadlocal' string is now - Setby_GGGGGGGGGG'. 
... 
      Thread [JJJJJJJJJJ] - Setby_GGGGGGGGGG'. 
Thread [JJJJJJJJJJ] complete. Our 'threadlocal' string is now - Setby_GGGGGGGGGG'. 
Thread [HHHHHHHHHH] complete. Our 'threadlocal' string is now - Setby_GGGGGGGGGG'. 
      Thread [GGGGGGGGGG] - Setby_GGGGGGGGGG'. 
Thread [GGGGGGGGGG] complete. Our 'threadlocal' string is now - Setby_GGGGGGGGGG'. 
      Thread [IIIIIIIIII] - Setby_GGGGGGGGGG'. 
      Thread [CCCCCCCCCC] - Setby_GGGGGGGGGG'. 
Thread [CCCCCCCCCC] complete. Our 'threadlocal' string is now - Setby_GGGGGGGGGG'. 
Thread [AAAAAAAAAA] complete. Our 'threadlocal' string is now - Setby_GGGGGGGGGG'. 
      Thread [DDDDDDDDDD] - Setby_GGGGGGGGGG'. 
Thread [DDDDDDDDDD] complete. Our 'threadlocal' string is now - Setby_GGGGGGGGGG'. 
Thread [IIIIIIIIII] complete. Our 'threadlocal' string is now - Setby_GGGGGGGGGG'. 
============== all threads complete. 

Я не включил класс, который создает, начинается, и соединяет нити - если это чувствовал, чтобы быть полезным, я с удовольствием редактировать, чтобы добавить его.

+0

Интересно, возникает ли проблема, что вы «начинаете» потоки, вызывая метод 'run()' вместо метода 'start()' ... –

+0

Спасибо за предложение, Стивен.Потоки запускаются с помощью метода start(), но это, безусловно, может иметь эффект. – CPerkins

ответ

5

Наличие отдельных экземпляров не помогает, поскольку все экземпляры имеют одинаковые статические поля. Смещаемая статика - это зло.

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

+0

Я знаю, что о статике вне threadlocal, но я подумал из обсуждений здесь и в другом месте, что threadlocal предоставил потоковые копии статики - превратив их в одно для потока, в отличие от одноразового загрузчика. Не так? – CPerkins

+0

'ThreadLocal' дает каждому потоку возможность иметь другую ссылку. Он не делает ничего волшебного. Вы даже можете установить одну и ту же ссылку в разных потоках и в итоге получить точно такой же объект. –

+0

Это неутешительно. Но спасибо. – CPerkins

2

Класс ThreadLocal не изменяет поведение модификатора статического поля. Статические поля будут по-прежнему иметь одно воплощение для нескольких экземпляров класса, поскольку они создаются и инициализируются при инициализации класса.

Чтобы пролить свет на это, члены ThreadLocal управляются внутренне с использованием Карты, которая существует для каждой нити. На этой карте действуют вызовы get() и set(). В ThreadLocal нет «магии», благодаря чему статический член теряет свое свойство иметь единственное воплощение. Статические элементы, заданные как переменная ThreadLocal, просто добавляются в Map для ссылки в другом разделе кода, который будет выполняться потоком. Это не мешает второму потоку получить ссылку на статический член и выполнять операции над полем-членом.

Именно по этой причине заявления Тома Хотина следует воспринимать всерьез - изменчивая статика просто не является хорошим дизайном.

PS: Взгляд на реализацию потоков ThreadLocal и ThreadLocal.ThreadLocalMap будет полезен в устранении любых заблуждений о поведении объектов ThreadLocal.

+0

Спасибо, я сделаю это. – CPerkins

Смежные вопросы