Существует разница между нитовыми переменными и членами потока. Класс Threadlocal предоставляет локальные переменные потока. Эта локальная переменная отличается от общих переменных членов. Когда потоковая переменная используется несколькими потоками, каждый поток может получить только одну копию переменной. Это описание в Java API. Читая исходный код API, я обнаружил, что это не копия. Что такое концепция копии? Клоны? Или что -то еще, слишком расплывчато.
Чтобы быть точным, реестр (Map <Thread, T>) внутри переменной типа Threadlocal изменился, но переменная типа Threadlocal действительно одна, и это сущность!
Вот пример:
1. Стандартные примеры
Определяется класс Mythreadlocal, и его объект TLT создается, и он используется четырьмя потоками. В результате переменные TLT четырех потоков не делятся. Второе - использовать свои собственные, что показывает, что в четырех потоках используется копия TLT (клон).
/*** Используйте Threadlocal Class*/Public Class Mythreadlocal {// Определите трентокальную переменную для сохранения int или Integer Data Private Threadlocal <Integer> tl = new Threadlocal <Integer> () {@override Protected Integer initierValue () {return 0; }}; public integer getNextnum () {// Получить значение TL и добавить 1 и обновить значение t1 tl.set (tl.get () + 1); вернуть tl.get (); }} / *** Тестовый поток*/ public class testthread extends {private mythreadlocal tlt = new mythreadlocal (); public Testthread (Mythreadlocal TLT) {this.tlt = tlt; } @Override public void run () {for (int i = 0; i <3; i ++) {System.out.println (thread.currentThread (). GetName () + "/t" + tlt.getNextnum ()); }}} / *** Threadlocal Test*/ public Class Test {public static void main (string [] args) {mythreadlocal tlt = new mythreadlocal (); Поток T1 = New TestThread (TLT); Поток T2 = New TestThread (TLT); Поток T3 = New TestThread (TLT); Поток T4 = New TestThread (TLT); t1.start (); t2.start (); t3.start (); t4.start (); }}
Видно, что три потока пронумерованы независимо и не влияют друг на друга:
Thread-0 1 Thread-1 1 Thread-0 2 Thread-1 2 Thread-0 3 Thread-1 3 Thread-2 1 Thread-3 1 Tread-2 2 Thread-3 Thread-2 3 Tread-3 3 Процесс завершен с кодом выхода 0
Объект TLT один, а бессмысленный TL-объект также является одним из них, потому что комбинированная взаимосвязь составляет один к одному. Однако по мере увеличения количества потоков будет создано многие целочисленные объекты. Это просто целое число и int уже распространено. Так что я не могу чувствовать свойства объекта целого числа.
2. Не используйте Threadlocal
Если вы не используете Threadlocal, вам просто нужно пересмотреть класс Mythreadlocal как:
/ *** Используйте Threadlocal Class*/ Public Class Mythreadlocal {Private Integer T1 = 0; public Integer getNextNum () {return t1 = t1+1; } // Определите трентокальную переменную для сохранения int или Integer Data // Private Threadlocal <Integer> tl = new Threadlocal <Integer> () {// @Override // Защищенное целое число initialValue () {// return 0; //} //}; // // public integer getNextNum () {// // Получить значение TL и добавить 1 и обновить значение t1 // tl.set (tl.get () + 1); // вернуть tl.get (); //}}
Затем запустите тест:
Тейд-2 1 Тейд-2 2 Тейд-1 4 4 резьба 6 Thread-3 3 Thread-3 9 Thread-3 10 Thread-1 8 Thread-0 7 Thread-0 11 Thread-0 12 Thread-2 5 Процесс завершен с кодом выхода 0
Отсюда мы видим, что четыре потока используют переменную TLT, и каждый поток напрямую изменяет свойства TLT.
3. осознавать нитолокал самостоятельно
пакет com.lavasoft.test2; импортировать java.util.collections; импортировать java.util.hashmap; импортировать java.util.map; /*** Используйте Threadlocal Class*/public Class Mythreadlocal {// Определите трентокальную переменную для сохранения int или integer data private com.lavasoft.test2.threadlocal <integer> tl = new com.lavasoft.test2.threadlocal <Integer> () { @@override protected inte integer internue () {return 0; }}; public integer getNextnum () {// Получить значение TL и добавить 1 и обновить значение t1 tl.set (tl.get () + 1); вернуть tl.get (); }} класс Threadlocal <T> {Private Map <Thread, t> map = collections.synchronizedmap (new hashmap <thread, t> ()); public ThinkLocal () {} защищенный t initialValue () {return null; } public t get () {thread t = thread.currentThread (); T obj = map.get (t); if (obj == null &&! map.containskey (t)) {obj = initialValue (); map.put (t, obj); } вернуть obj; } public void set (t value) {map.put (thread.currentThread (), value); } public void remove () {map.remove (thread.currentThread ()); }}
Запустите тест:
Thread-0 1 Thread-0 2 Thread-0 3 Thread-2 1 Thread-2 2 Tread-3 1 Thread-2 3 Thread-3 Thread-1 1 Tread-3 3 Thread-1 2 Tread-1 3 Процесс завершен с кодом выхода 0
Удивительно, но эта версия Threadlocal также работает хорошо, реализуя функцию Threadlocal в Java API.
4. См. Суть через явления
На самом деле, с точки зрения программы, переменная TLT действительно одна, без сомнения. Но почему печатные числа не влияют друг на друга?
Это из -за использования целого числа? -----нет.
Причина в том, что защищен t initialValue () и get (), потому что, когда каждый поток вызовет get (), он создаст его, если его не существует на карте. Когда он называется, новая переменная создается с типом T. Каждый раз, когда они создаются, конечно, каждый из них использует их без какого -либо влияния друг на друга.
Чтобы четко увидеть суть, замените целое число и перепишите некоторые классы:
пакет com.lavasoft.test2; импортировать java.util.collections; импортировать java.util.hashmap; импортировать java.util.map; /*** Используйте Threadlocal Class*/Public Class Mythreadlocal {// Определите трентокальную переменную для сохранения int или integer data // private threadlocal <bean> tl = new Threadlocal <Fean> () {private com.lavasoft.test2.threadlocal <Bean> tl = new Com.lavasoft.Test.Threcle.Threclocal <Bean> tl = new Com.lavasoft.Test.Threclocal <Bean> tl = new Com.lavasoft.Threcle.Thret.Thret2.thread. @Override защищен Bean initialValue () {return new Bean (); }}; @Override public String toString () {return "mythreadlocal {" + "tl =" + tl + '}'; } public bean getBean () {return tl.get (); }} класс Threadlocal <T> {Private Map <Thread, t> map = collections.synchronizedmap (new hashmap <thread, t> ()); public ThinkLocal () {} защищенный t initialValue () {return null; } public t get () {thread t = thread.currentThread (); T obj = map.get (t); if (obj == null &&! map.containskey (t)) {obj = initialValue (); map.put (t, obj); } вернуть obj; } public void set (t value) {map.put (thread.currentThread (), value); } public void remove () {map.remove (thread.currentThread ()); }} пакет com.lavasoft.test2; / ** * Test Bean */ Public Class Bean {Private String id = "0"; Приватная строка name = "none"; public bean () {} public bean (String Id, String name) {this.id = id; this.name = name; } public String getId () {return id; } public void setId (String id) {this.id = id; } public String getName () {return name; } public void setName (string name) {this.name = name; } public String showinfo () {return "bean {" + "id = '" + id +'/'' + ", name = '" + name +'/'' + '}'; }} пакет com.lavasoft.test2; / *** Тестовый поток*/ public class testthread extends {private mythreadlocal tlt = new mythreadlocal (); public Testthread (Mythreadlocal TLT) {this.tlt = tlt; } @Override public void run () {System.out.println (">>>>:" + tlt); for (int i = 0; i <3; i ++) {System.out.println (thread.currentThread (). getName ()+"/t"+tlt.getbean ()+"/t"+tlt.getbean (). Showinfo ()); }}}
Затем запустите тест:
>>>>>: mythreadlocal <tl=com.lavasoft.test2.mythreadlocalD1@1de3f2d} >>>>>: mythreadlocalти >>>>>: mythreadlocal <tl=com.lavasoft.test2.bean@291aff Bean {id = '0', name = 'none'} thread-2 com.lavasoft.test2.bean@fe64b9 bean {id = '0', name = none '} thread-3 com.lavasoft.test2.bean@186 Bean{id='0', name='none'} Thread-2 com.lavasoft.test2.Bean@fe64b9 Bean{id='0', name='none'} Thread-2 com.lavasoft.test2.Bean@fe64b9 Bean{id='0', name='none'} Thread-2 com.lavasoft.test2.Bean@fe64b9 Bean {id = '0', name = 'none'} thread-0 com.lavasoft.test2.bean@291aff bean {id = '0', name = 'non'} thread-3 com.lavasoft.test2.bean@186db54 bean {id = '0', name = '} think-3 com.lavasoft.teest. Bean {id = '0', name = 'none'} thread-1 com.lavasoft.test2.bean@291aff bean {id = '0', name = 'none'} thread-0 com.lavasoft.test2.bean@291aff bean {id = '0', name = '} thread-0 com.lavasoft.test.beant.beant.bean@291 Bean {id = '0', name = 'none'} thread-1 com.lavasoft.test2.bean@291aff bean {id = '0', name = 'none'} процесс, законченное с кодом выхода 0
Из результатов печати ясно, что объект TLT Mythreadlocal действительно один, а объект TL Threadlocal в объекте TLT также является одним. Однако, когда T1T используется для каждого потока, поток будет воссоздать объект бобов и добавить его в карту Threadlocal для использования.
Несколько недоразумений о Threadlocal:
1. Threadlocal - это реализация Java Threads
Threadlocal действительно связан с потоками Java, но это не реализация потоков Java, он просто используется для поддержания локальных переменных. Для каждого потока он предоставляет свою собственную переменную версию, в основном, чтобы избежать конфликтов потоков, и каждый поток сохраняет свою собственную версию. Быть независимыми друг от друга, и модификация не повлияет друг на друга.
2. Threadlocal относительно каждого сеанса
Threadlocal, как следует из названия, предназначена для потоков. В веб -программировании Java каждый пользователь имеет свой собственный идентификатор сеанса с начала до конца сеанса. Но Threadlocal не на слое сеанса. На самом деле, Threadlocal не зависит от сеанса пользователя. Это поведение на стороне сервера. Всякий раз, когда сервер генерирует новый поток, он поддерживает свой собственный Threadlocal.
Что касается этого недоразумения, я лично считаю, что оно должно быть результатом локального теста разработчика на основе некоторых серверов приложений. Как мы все знаем, общие серверы приложений поддерживают набор пулов потоков, то есть для каждого доступа новый поток не обязательно генерирует. Вместо этого у меня есть пул кеша. Для доступа сначала найдите существующие потоки из пула кэша. Если они все избавились, то будет сгенерировать новый поток.
Следовательно, поскольку разработчик обычно является единственным, кто тестирует себя, бремя сервера очень мало, что приводит к обмену одному и тому же потоке каждый раз, когда доступ, что приводит к недопониманию: у каждого сеанса есть нитолокальный
3. Threadlocal относится к каждой потоке. Каждый раз, когда пользователь обращается, будет новый Threadlocal.
Теоретически, нитолокал действительно относится к каждому потоку, каждый поток будет иметь свой собственный нитокальный. Но, как упоминалось выше, общие серверы приложений поддерживают набор пулов потоков. Следовательно, разные пользователи могут получать один и тот же поток. Поэтому при выполнении загрязнения, вы должны быть осторожны, чтобы избежать кэша с нитокальными переменными, что приводит к тому, что другие потоки получают доступ к переменным потока.
4. Для каждого доступа пользователя можно использовать Threadlocal несколько раз.
Можно сказать, что Threadlocal является обоюдоострым мечом, и может иметь очень хорошие результаты, если они используются. Однако, если Threadlocal не используется хорошо, он будет таким же, как глобальные переменные. Код не может быть использован повторно и не может быть проверен независимо. Потому что некоторые классы, которые могли быть повторно использованы, теперь полагаются на переменную потока. Если нет нитолокального, эти классы становятся недоступными. Я лично думаю, что Threadlocal хорошо используется и стоит ссылаться на
1. Храните текущий пользователь сеанса: Quake Want Jert
2. Храните некоторые контекстные переменные, такие как ActionContext WebWork
3. Сессии магазина, такие как Spring Hibernate Orm Sessions