لا يزال هناك فرق بين متغيرات Threadlocal و Thread Member. يوفر الفئة threadlocal المتغيرات المحلية. يختلف هذا المتغير المحلي عن متغيرات الأعضاء العامة. عند استخدام متغير ThreadLocal بواسطة مؤشرات ترابط متعددة ، يمكن لكل مؤشر ترابط الحصول على نسخة واحدة فقط من المتغير. هذا وصف في Java API. من خلال قراءة رمز مصدر API ، وجدت أنها ليست نسخة. ما هو مفهوم النسخة؟ استنساخ؟ أو أي شيء آخر غامض للغاية.
لكي نكون دقيقًا ، تغير السجل (الخريطة <مؤشر الترابط ، t>) داخل متغير Type ThreadLocal ، لكن متغير النوع threadlocal نفسه هو بالفعل واحد ، وهذا هو الجوهر!
هنا مثال:
1. أمثلة قياسية
يتم تعريف فئة MyThreadlocal ، ويتم إنشاء كائنها tlt ، ويتم استخدامه بواسطة أربعة مؤشرات ترابط. نتيجة لذلك ، لا تشارك متغيرات TLT في المواضيع الأربعة. والثاني هو استخدام خاص بهم ، مما يدل على أن المواضيع الأربعة تستخدم نسخة من TLT (استنساخ).
/*** استخدم threadlocal class*/class public myThreadLocal {// تحديد متغير threadlocal لحفظ بيانات int أو integer private threadlocal <integer> tl = new threadlocal <integer> () {override internalvalue inirteger () {return 0 ؛ }} ؛ integer getNextNum () {// احصل على قيمة TL وإضافة 1 ، وتحديث قيمة T1 tl.set (tl.get () + 1) ؛ إرجاع tl.get () ؛ }} / *** TESTHOND THE THE THE THE TREHT TESTHREAD يمتد THELD {private myThReadLocal tlt = new MyThReadLocal () ؛ TestTresThread العام (mythreadlocal tlt) {this.tlt = tlt ؛ } Override public void run () {for (int i = 0 ؛ i <3 ؛ i ++) {system.out.println (thread.currentTherD (). getName () + "/t" + tlt.getNextNum ()) ؛ }}} / *** threadlocal test*/ test class public {public static void main (string [] args) {mythreadlocal tlt = new MyThreadLocal () ؛ الموضوع T1 = TestTresTread جديد (TLT) ؛ الموضوع T2 = TestTresThread جديد (TLT) ؛ الموضوع T3 = TestTresThread جديد (TLT) ؛ الموضوع T4 = TestTresThread جديد (TLT) ؛ t1.start () ؛ t2.start () ؛ t3.start () ؛ t4.start () ؛ }}
يمكن ملاحظة أن الخيوط الثلاثة مرقمة بشكل مستقل ولا تؤثر على بعضها البعض:
Thread-0 1 Thread 1 1 Thread-0 2 Thread-1 Thread-0 3 Thread-1 3 Thread-2 1 Thread-3 1 Thread-2 2 Thread-3 2 Thread-3 Thread-3 3 Process مع رمز الخروج 0
كائن TLT هو واحد ، وكائن TL الهراء هو أيضًا واحد ، لأن العلاقة المركب هي واحدة لواحد. ومع ذلك ، مع زيادة عدد المواضيع ، سيتم إنشاء العديد من كائنات عدد صحيح. إنه مجرد عدد صحيح و int شائع بالفعل. لذلك لا أستطيع أن أشعر بخصائص كائن عدد صحيح.
2. لا تستخدم threadlocal
إذا لم تستخدم ThreadLocal ، فأنت بحاجة فقط إلى إعادة تعريف فئة MyThreadlocal على النحو التالي:
/ *** استخدم threadlocal class*/ public class myThreadLocal {private integer t1 = 0 ؛ عدد صحيح عام getNextNum () {return t1 = t1+1 ؛ }. //} //} ؛ // // integer public getNextNum () {// // احصل على قيمة tl وإضافة 1 ، وقم بتحديث قيمة t1 // tl.set (tl.get () + 1) ؛ // return tl.get () ؛ //}}
ثم قم بإجراء الاختبار:
Thread-2 1 Thread-2 Thread-1 4 thread-1 6 thread-3 3 thread-3 9 thread-3 10 thread-1 8 thread-0 7 thread-0 11 thread-0 thread-2 5 process with with exit code 0
من هنا ، يمكننا أن نرى أن مؤشرات الترابط الأربعة تشترك في متغير TLT ، وأن كل مؤشر ترابط يعدل مباشرة خصائص TLT.
3. إدراك Threadlocal بنفسك
حزمة com.lavasoft.test2 ؛ استيراد java.util.collections ؛ استيراد java.util.hashmap ؛ استيراد java.util.map ؛ /*** استخدم classlocal threadlocal*/الفئة العامة myThreadLocal {// تحديد متغير threadlocal لحفظ بيانات int أو integer private com.lavasoft.test2.Threadlocal <integer> tl = new com.lavasoft.test2 }} ؛ integer getNextNum () {// احصل على قيمة TL وإضافة 1 ، وتحديث قيمة T1 tl.set (tl.get () + 1) ؛ إرجاع tl.get () ؛ }} class threadlocal <T> {private map <froof ، t> map = collections.synchronizedMap (new hashmap <froof ، t> ()) ؛ public threadlocal () {} محمية 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 ؛ } مجموعة void العامة (قيمة t) {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 Thread-3 1 Thread-2 3 Thread-3 2 Thread-1 1 Thread-3 3 Thread-1 Thread-1 3 Process مع رمز الخروج 0
من المثير للدهشة أن هذا النسخة المقلدة من ThreadLocal تعمل بشكل جيد أيضًا ، حيث تنفذ وظيفة ThreadLocal في Java API.
4. انظر الجوهر من خلال الظواهر
في الواقع ، من منظور البرنامج ، فإن متغير TLT هو بالفعل واحد ، بلا شك. ولكن لماذا لا تؤثر الأرقام المطبوعة على بعضها البعض؟
هل هو بسبب استخدام عدد صحيح؟ -----لا.
والسبب هو: محمي t initialValue () والحصول على () ، لأنه عندما يحصل كل مؤشرات ترابط على () ، فإنه سيتم إنشاؤه إذا لم يكن موجودًا في الخريطة. عندما يتم استدعاؤه ، يتم إنشاء متغير جديد مع Type T. في كل مرة يتم إنشاؤها حديثًا ، بالطبع ، يستخدم كل واحد منها دون أي تأثير على بعضها البعض.
من أجل رؤية الجوهر بوضوح ، استبدل عدد صحيح وإعادة كتابة بعض الفصول:
حزمة com.lavasoft.test2 ؛ استيراد java.util.collections ؛ استيراد java.util.hashmap ؛ استيراد java.util.map ؛ /*** استخدم threadlocal class*/الفئة العامة myThreadLocal {// تحديد متغير threadlocal لحفظ بيانات int أو integer // private threadlocal <bean> tl = new threadlocal <bean> () {private com.lavasoft.test2.Threadlocal <ban> tl = new com.lavasoft.test.test2. initialValue () {return new Bean () ؛ }} ؛ Override public string toString () {return "myThReadLocal {" + "tl =" + tl + '}' ؛ } public bean getBean () {return tl.get () ؛ }} class threadlocal <T> {private map <froof ، t> map = collections.synchronizedMap (new hashmap <froof ، t> ()) ؛ public threadlocal () {} محمية 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 ؛ } مجموعة void العامة (قيمة t) {map.put (thread.currentThread () ، value) ؛ } public void remove () {map.remove (thread.currentThread ()) ؛ }} حزمة com.lavasoft.test2 ؛ / ** * اختبار Bean */ Public Class Bean {Private String ID = "0" ؛ اسم السلسلة الخاصة = "لا شيء" ؛ Public Bean () {} Public Bean (معرف السلسلة ، اسم السلسلة) {this.id = id ؛ this.name = name ؛ } السلسلة العامة getId () {return id ؛ } public void setId (string id) {this.id = id ؛ } السلسلة العامة getName () {return name ؛ } public void setName (اسم السلسلة) {this.name = name ؛ } السلسلة العامة showInfo () {return "bean {" + "id =" " + id + '/' ' +" ، name = " + name +'/' +'} '؛ }} حزمة com.lavasoft.test2 ؛ / *** TESTHOND THE THE THE THE TREHT TESTHREAD يمتد THELD {private myThReadLocal tlt = new MyThReadLocal () ؛ TestTresThread العام (mythreadlocal tlt) {this.tlt = tlt ؛ } Override public void run () {system.out.println (">>>>:" + tlt) ؛ لـ (int i = 0 ؛ i <3 ؛ i ++) {system.out.println (thread.currentTherAd (). }}}
ثم قم بإجراء الاختبار:
>>>>>: myThreadLocal {tl=com.lavasoft.test2 >>>>>>: myThreadLocal {tlacom.lavasoft.test2 name = 'none'} thread-2 com.lavasoft.test2.bean@fe64b9 bean {id = '0' ، name = 'none'} thread-2 com.lavasoft.test2.bean@fe64b9 bean {id = '0' ، nome = ' com.lavasoft.test2.bean@291aff bean {id = 0 '، name =' none '} thread-3 com.lavasoft.test2 com.lavasoft.test2.bean@291aff bean {id = 0 '، name =' none '} thread-0 com.lavasoft.test2 com.lavasoft.test2.bean@291aff bean {id = '0' ، name = 'none'} انتهى مع رمز الخروج 0
يتضح من نتائج الطباعة أن كائن TLT الخاص بـ MyThreadlocal هو بالفعل واحد ، وكائن TL الخاص بـ threadlocal في كائن TLT هو أيضًا واحد. ومع ذلك ، عند استخدام T1T لكل مؤشر ترابط ، سيقوم مؤشر الترابط بإعادة إنشاء كائن Bean وإضافته إلى خريطة Threadlocal للاستخدام.
العديد من سوء الفهم حول threadlocal:
1. Threadlocal هو تنفيذ مؤشرات ترابط Java
يرتبط ThreadLocal بالفعل بخيوط Java ، لكنه ليس تطبيقًا لخيوط Java ، فهو يستخدم فقط للحفاظ على المتغيرات المحلية. لكل مؤشر ترابط ، يوفر إصداره المتغير الخاص به ، وذلك أساسًا لتجنب تعارضات مؤشرات الترابط ، ويحافظ كل مؤشر ترابط على نسخته الخاصة. كن مستقلاً عن بعضنا البعض ، ولن يؤثر التعديل على بعضها البعض.
2. Threadlocal نسبة إلى كل جلسة
ThreadLocal ، كما يوحي الاسم ، يهدف إلى المواضيع. في برنامج Java Web Programming ، لدى كل مستخدم معرف الجلسة الخاص به من البداية إلى نهاية الجلسة. لكن Threadlocal ليس على طبقة الجلسة. في الواقع ، ThreadLocal مستقل عن جلسة المستخدم. إنه سلوك من جانب الخادم. كلما قام الخادم بإنشاء مؤشر ترابط جديد ، فإنه يحافظ على ThreadLocal الخاص به.
فيما يتعلق بهذا سوء الفهم ، أعتقد شخصيا أنه يجب أن يكون نتيجة للاختبار المحلي للمطور استنادًا إلى بعض خوادم التطبيق. كما نعلم جميعًا ، تحتفظ خوادم التطبيق العامة بمجموعة من تجمعات الخيوط ، أي لكل وصول ، لا يتم إنشاء مؤشر ترابط جديد بالضرورة. بدلاً من ذلك ، لدي تجمع ذاكرة التخزين المؤقت للخيوط. للوصول ، ابحث أولاً عن المواضيع الموجودة من تجمع ذاكرة التخزين المؤقت. إذا استخدموا كل شيء ، فسيتم إنشاء موضوع جديد.
لذلك ، نظرًا لأن المطور عادة ما يكون الشخص الوحيد الذي يختبر نفسه ، فإن عبء الخادم صغير جدًا ، مما يؤدي إلى مشاركة نفس الخيط في كل مرة يكون فيها الوصول ، مما يؤدي
3. Threadlocal نسبة إلى كل مؤشر ترابط. في كل مرة يصل المستخدم ، سيكون هناك مؤشر ترابط جديد.
من الناحية النظرية ، يكون ThreadLocal بالفعل بالنسبة إلى كل مؤشر ترابط ، سيكون لكل مؤشر ترابطه الخاص. ولكن كما ذكر أعلاه ، تحافظ خوادم التطبيق العامة على مجموعة من تجمعات الخيوط. لذلك ، قد يتلقى المستخدمون المختلفين نفس الموضوع. لذلك ، عند القيام بالمؤسسة ذات العوامل الرئيسية ، يجب أن تكون حريصًا على تجنب ذاكرة التخزين المؤقت للمتغيرات الخيطية ، مما يؤدي إلى الوصول إلى متغيرات مؤشرات الترابط
4. لكل وصول مستخدم ، يمكن استخدام ThreadLocal عدة مرات.
يمكن القول أن ThreadLocal هو سيف ذو حدين ، ويمكن أن يكون له نتائج جيدة جدًا إذا تم استخدامه. ومع ذلك ، إذا لم يتم استخدام ThreadLocal بشكل جيد ، فسيكون هو نفسه المتغيرات العالمية. لا يمكن إعادة استخدام الكود ولا يمكن اختباره بشكل مستقل. لأن بعض الفصول التي كان يمكن إعادة استخدامها تعتمد الآن على المتغير الخيط. إذا لم يكن هناك Threadlocal ، فإن هذه الفئات تصبح غير متوفرة. أنا شخصياً أعتقد أن threadlocal يستخدم بشكل جيد ويستحق الإشارة إلى
1. قم بتخزين مستخدم الجلسة الحالي: Quake Want Jert
2. قم بتخزين بعض متغيرات السياق ، مثل WebWork's ActionContext
3. جلسات تخزين ، مثل جلسات الربيع السباتية