سؤال

متى يجب أن أستخدم أ ThreadLocal عامل؟

كيف يتم استخدامه؟

هل كانت مفيدة؟

المحلول

واحد ممكن (والمشترك) الاستخدام هو عندما يكون لديك بعض وجوه غير موضوع آمنة، ولكن كنت ترغب في تجنب <لأ href = "https://docs.oracle.com/javase/tutorial/essential/concurrency /sync.html "يختلط =" noreferrer "> مزامنة الوصول إلى هذا الكائن (أنا أبحث في لكم، <وأ href =" https://docs.oracle.com/javase/8/docs/api /java/text/SimpleDateFormat.html "يختلط =" noreferrer "> SimpleDateFormat ). بدلا من ذلك، وإعطاء كل موضوع المثال الخاص للكائن.

وعلى سبيل المثال:

public class Foo
{
    // SimpleDateFormat is not thread-safe, so give one to each thread
    private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
        @Override
        protected SimpleDateFormat initialValue()
        {
            return new SimpleDateFormat("yyyyMMdd HHmm");
        }
    };

    public String formatIt(Date date)
    {
        return formatter.get().format(date);
    }
}

الوثائق .

نصائح أخرى

منذ أ ThreadLocal هو إشارة إلى البيانات داخل معين Thread, ، قد ينتهي بك الأمر إلى حدوث تسريبات في تحميل الفصل عند الاستخدام ThreadLocalفي خوادم التطبيقات باستخدام تجمعات الخيوط.يجب أن تكون حذرًا للغاية بشأن تنظيف أي منها ThreadLocalأنت get() أو set() باستخدام ThreadLocalremove() طريقة.

إذا لم تقم بالتنظيف عند الانتهاء، فإن أي مراجع تتضمنها للفئات التي تم تحميلها كجزء من تطبيق ويب منشور ستبقى في كومة دائمة ولن يتم جمع القمامة أبدًا.لن تؤدي إعادة نشر/إلغاء نشر تطبيق الويب إلى تنظيف كلٍ منهما Threadإشارة إلى فئة (فصول) تطبيق الويب الخاص بك منذ Thread ليس شيئًا مملوكًا لتطبيق الويب الخاص بك.سيؤدي كل نشر متتالي إلى إنشاء مثيل جديد للفئة التي لن يتم تجميع البيانات المهملة فيها مطلقًا.

سوف ينتهي بك الأمر مع نفاد استثناءات الذاكرة بسبب java.lang.OutOfMemoryError: PermGen space وبعد بعض البحث على جوجل ربما يزيد فقط -XX:MaxPermSize بدلاً من إصلاح الخلل.

إذا واجهت هذه المشكلات في النهاية، فيمكنك تحديد مؤشر الترابط والفئة التي تحتفظ بهذه المراجع باستخدام محلل ذاكرة Eclipse و/أو عن طريق المتابعة دليل فرانك كييفيت و متابعة.

تحديث:اعاد اكتشاف دخول مدونة Alex Vasseur التي ساعدتني على تعقب بعض ThreadLocal القضايا التي كنت أواجهها.

والعديد من الأطر استخدام ThreadLocals للحفاظ على بعض سياق متصل إلى الترابط الحالي. على سبيل المثال عندما يتم تخزين المعاملة الحالية في ThreadLocal، لا تحتاج إلى تمريرها كمعلمة من خلال كل استدعاء الأسلوب، في حالة شخص أسفل كومة يحتاج إلى الوصول إليها. تطبيقات الويب قد تخزين المعلومات حول الطلب الحالي والدورة في وThreadLocal، بحيث تطبيق وسهولة الوصول إليها. مع Guice يمكنك استخدام ThreadLocals عند تنفيذ نطاقات مخصصة للكائنات حقن (الافتراضي Guice ل< وأ href = "https://github.com/google/guice/wiki/Scopes" يختلط = "نوفولو noreferrer"> نطاقات بريمج على الأرجح استخدامها كذلك).

وThreadLocals هي نوع واحد من المتغيرات العالمية (على الرغم من أن أقل قليلا الشر لأنها تقتصر على موضوع واحد)، لذلك يجب أن تكون حذرا عند استخدامها لتجنب التأثيرات الجانبية غير المرغوبة وتسرب الذاكرة. تصميم واجهات برمجة التطبيقات الخاصة بك بحيث دائما يتم مسح القيم ThreadLocal تلقائيا عندما لا تكون هناك حاجة إليها بعد الآن، وسوف أن الاستخدام غير الصحيح من API لن يكون ممكنا (على سبيل المثال <لأ href = "https://github.com/orfjackal/dimdwarf /blob/453f7aee9efc364ebad80531c05081e255323c07/dimdwarf-core/src/main/java/net/orfjackal/dimdwarf/context/ThreadContext.java#L48-55 "يختلط =" نوفولو noreferrer "> مثل هذا ). ThreadLocals يمكن استخدامها لجعل نظافة الرمز، وفي بعض الحالات النادرة التي هي السبيل الوحيد لجعل عمل شيء (كان مشروعي الحالي اثنتين من هذه الحالات، ويتم توثيقها <لأ href = "https://github.com/orfjackal / dimdwarf / ويكي / التصميم المبادئ التوجيهية "يختلط =" نوفولو noreferrer "> هنا تحت عنوان" حقول ثابت والمتغيرات العالمية ").

في جاوة، إذا كان لديك مسند التي يمكن أن تختلف لكل موضوع، والخيارات الخاصة بك لتمرير مسند جميع أنحاء لكل طريقة التي تحتاج (أو حاجة)، أو لربط مسند مع الموضوع. تمرير مسند حولها في كل مكان قد تكون قابلة للتطبيق إذا كان كل وسائل الخاص بك تحتاج بالفعل لتمرير حول "السياق" متغير مشترك.

وإذا كان هذا ليس هو الحال، قد لا ترغب في فوضى حتى التوقيعات طريقتك مع معلمة إضافية. في عالم غير مترابطة، هل يمكن أن تحل المشكلة مع ما يعادل جافا متغير العالمي. في كلمة واحدة مترابطة، أي ما يعادل متغير عمومي غير متغير موضوع المحلي.

هناك مثال جيد جدا في الكتاب جافا التزامن في الممارسة العملية.حيث المؤلف (جوشوا بلوخ) يشرح كيف أن حبس الخيط هو أحد أبسط الطرق لتحقيق سلامة الخيط و ThreadLocal هي وسيلة أكثر رسمية للحفاظ على حبس الخيط.وفي النهاية شرح أيضًا كيف يمكن للناس إساءة استخدامه باستخدامه كمتغيرات عالمية.

لقد قمت بنسخ النص من الكتاب المذكور ولكن الكود 3.10 مفقود لأنه ليس من المهم أن نفهم أين يجب استخدام ThreadLocal.

غالبًا ما تُستخدم متغيرات مؤشر الترابط المحلي لمنع المشاركة في التصميمات المستندة إلى متغيرات فردية أو متغيرات عامة قابلة للتغيير.على سبيل المثال، قد يحتفظ تطبيق أحادي الترابط باتصال قاعدة بيانات عمومية تتم تهيئته عند بدء التشغيل لتجنب الاضطرار إلى تمرير اتصال إلى كل أسلوب.نظرًا لأن اتصالات JDBC قد لا تكون آمنة لسلسلة العمليات، فإن التطبيق متعدد الخيوط الذي يستخدم اتصالاً عامًا دون تنسيق إضافي ليس آمنًا لسلسلة العمليات أيضًا.باستخدام ThreadLocal لتخزين اتصال JDBC، كما هو الحال في ConnectionHolder في القائمة 3.10، سيكون لكل مؤشر ترابط اتصاله الخاص.

يستخدم ThreadLocal على نطاق واسع في تنفيذ أطر التطبيقات.على سبيل المثال، تقوم حاويات J2EE بربط سياق المعاملة بسلسلة تنفيذ طوال مدة استدعاء EJB.يتم تنفيذ ذلك بسهولة باستخدام مؤشر ترابط محلي ثابت يحمل سياق المعاملة:عندما يحتاج رمز إطار العمل إلى تحديد المعاملة قيد التشغيل حاليًا، فإنه يجلب سياق المعاملة من ThreadLocal.يعد هذا مناسبًا لأنه يقلل من الحاجة إلى تمرير معلومات سياق التنفيذ إلى كل طريقة، ولكنه يربط أي كود يستخدم هذه الآلية بإطار العمل.

من السهل إساءة استخدام ThreadLocal من خلال التعامل مع خاصية تقييد مؤشر الترابط الخاصة به كترخيص لاستخدام المتغيرات العامة أو كوسيلة لإنشاء وسيطات أسلوب "مخفية".مثل المتغيرات العامة، يمكن للمتغيرات المحلية أن تقلل من إمكانية إعادة الاستخدام وتقدم أدوات توصيل مخفية بين الفئات، وبالتالي يجب استخدامها بحذر.

في الأساس، عندما تحتاج إلى تعتمد قيمة المتغير على مؤشر الترابط الحالي وهذا ليس من المناسب لك إرفاق القيمة بمؤشر الترابط بطريقة أخرى (على سبيل المثال، موضوع فئة فرعية).

حالة نموذجية هي أين قام إطار عمل آخر بإنشاء الموضوع أن التعليمات البرمجية الخاصة بك قيد التشغيل، على سبيل المثال.حاوية servlet، أو حيث يكون استخدام ThreadLocal أكثر منطقية لأن المتغير الخاص بك يكون بعد ذلك "في مكانه المنطقي" (بدلاً من متغير معلق من فئة فرعية لمؤشر الترابط أو في خريطة تجزئة أخرى).

على موقع الويب الخاص بي، لدي المزيد مناقشة وأمثلة حول متى يتم استخدام ThreadLocal قد يكون ذلك أيضًا موضع اهتمام.

يدافع بعض الأشخاص عن استخدام ThreadLocal كوسيلة لإرفاق "معرف مؤشر الترابط" بكل موضوع في خوارزميات متزامنة معينة حيث تحتاج إلى رقم مؤشر الترابط (انظر على سبيل المثال.هيرليهي وشافيت).في مثل هذه الحالات، تأكد من أنك تحصل بالفعل على فائدة!

وثائق يقول ذلك بشكل جيد جدا : "كل موضوع أن يصل [متغير موضوع محلي] (عن طريق الحصول على طريقة أو مجموعة) لديها قناعاتها، نسخته تهيئة بشكل مستقل عن المتغير"

ويمكنك استخدام واحد عندما يجب أن يكون كل موضوع نسخته شيء. افتراضيا، يتم تبادل البيانات بين المواضيع.

والخادم تطبيق الويب قد حفاظ على ترابط التجمع، وينبغي إزالة ThreadLocal فار قبل الاستجابة إلى العميل، وبالتالي يمكن إعادة استخدامها الترابط الحالي حسب الطلب القادم.

  1. تم تقديم ThreadLocal في Java في JDK 1.2 ولكن تم إنشاؤه لاحقًا في JDK 1.5 لتقديم أمان النوع في متغير ThreadLocal.

  2. يمكن ربط ThreadLocal بنطاق Thread، فكل التعليمات البرمجية التي يتم تنفيذها بواسطة Thread لديها حق الوصول إلى متغيرات ThreadLocal ولكن لا يمكن لخيطين رؤية متغير ThreadLocal لبعضهما البعض.

  3. يحتوي كل مؤشر ترابط على نسخة حصرية من متغير ThreadLocal الذي يصبح مؤهلاً لجمع البيانات المهملة بعد انتهاء مؤشر الترابط أو وفاته، عادةً أو بسبب أي استثناء، نظرًا لأن متغير ThreadLocal لا يحتوي على أي مراجع مباشرة أخرى.

  4. تعد متغيرات ThreadLocal في Java عمومًا حقولًا ثابتة خاصة في الفئات وتحافظ على حالتها داخل Thread.

اقرأ أكثر: ThreadLocal في Java - مثال للبرنامج والبرامج التعليمية

واثنين من حالات الاستخدام حيث يمكن استخدام متغير threadlocal - منتديات 1- عندما يكون لدينا شرط لربط الدولة مع موضوع (على سبيل المثال، هوية المستخدم أو هوية عملية). ما يحدث عادة مع تطبيق على شبكة الإنترنت أن كل طلب الذهاب الى بريمج لديه transactionID فريدة من نوعها المرتبطة به.

// This class will provide a thread local variable which
// will provide a unique ID for each thread
class ThreadId {
    // Atomic integer containing the next thread ID to be assigned
    private static final AtomicInteger nextId = new AtomicInteger(0);

    // Thread local variable containing each thread's ID
    private static final ThreadLocal<Integer> threadId =
        ThreadLocal.<Integer>withInitial(()-> {return nextId.getAndIncrement();});

    // Returns the current thread's unique ID, assigning it if necessary
    public static int get() {
        return threadId.get();
    }
}

لاحظ أن هنا طريقة يتم تنفيذ withInitial باستخدام التعبير امدا.
2- استخدام آخر الحالة هو عندما نريد أن يكون مثيل آمن موضوع، ونحن لا نريد أن استخدام تزامن حيث تبلغ تكلفة أداء تزامن مع ما هو أكثر. واحدة من هذه القضية عند استخدام SimpleDateFormat. منذ SimpleDateFormat لا ترابط آمن لذلك لدينا لتوفير آلية لجعلها ذات ألوان.

public class ThreadLocalDemo1 implements Runnable {
    // threadlocal variable is created
    private static final ThreadLocal<SimpleDateFormat> dateFormat = new ThreadLocal<SimpleDateFormat>(){
        @Override
        protected SimpleDateFormat initialValue(){
            System.out.println("Initializing SimpleDateFormat for - " + Thread.currentThread().getName() );
            return new SimpleDateFormat("dd/MM/yyyy");
        }
    };

    public static void main(String[] args) {
        ThreadLocalDemo1 td = new ThreadLocalDemo1();
        // Two threads are created
        Thread t1 = new Thread(td, "Thread-1");
        Thread t2 = new Thread(td, "Thread-2");
        t1.start();
        t2.start();
    }

    @Override
    public void run() {
        System.out.println("Thread run execution started for " + Thread.currentThread().getName());
        System.out.println("Date formatter pattern is  " + dateFormat.get().toPattern());
        System.out.println("Formatted date is " + dateFormat.get().format(new Date()));
    } 

}

منذ إصدار Java 8، هناك طريقة أكثر وضوحًا للتهيئة ThreadLocal:

ThreadLocal<Cipher> local = ThreadLocal.withInitial(() -> "init value");

حتى إصدار Java 8، كان عليك القيام بما يلي:

ThreadLocal<String> local = new ThreadLocal<String>(){
    @Override
    protected String initialValue() {
        return "init value";
    }
};

علاوة على ذلك، إذا كانت طريقة إنشاء مثيل (المنشئ، طريقة المصنع) للفئة المستخدمة ThreadLocal لا يأخذ أي معلمات، يمكنك ببساطة استخدام مراجع الطريقة (المقدمة في Java 8):

class NotThreadSafe {
    // no parameters
    public NotThreadSafe(){}
}

ThreadLocal<NotThreadSafe> container = ThreadLocal.withInitial(NotThreadSafe::new);

ملحوظة:التقييم كسول منذ اجتيازك java.util.function.Supplier لامدا التي يتم تقييمها فقط عندما ThreadLocal#get يتم استدعاؤه ولكن لم يتم تقييم القيمة مسبقًا.

وعليك أن تكون حذرا جدا مع نمط ThreadLocal. هناك بعض الاطراف أسفل الكبرى مثل ذكر فيل، ولكن ذلك لم يذكر هو التأكد من أن التعليمات البرمجية التي يضع سياق ThreadLocal ليس "إعادة الوافد".

وأشياء سيئة يمكن أن يحدث عندما يحصل تشغيل التعليمات البرمجية التي تضع المعلومات للمرة الثانية أو الثالثة لأن المعلومات عن موضوع الخاص بك يمكن أن تبدأ على التحور عندما كنت لا أتوقع ذلك. حتى تأخذ الرعاية للتأكد من لم يتم تعيين معلومات ThreadLocal قبل تعيينها مرة أخرى.

ومتى؟

عند كائن ليس الخيط آمنة، بدلا من التزامن الذي يعيق قابلية، وإعطاء كائن واحد في كل موضوع وابقائه خيط نطاق، وهو ThreadLocal. واحدة من الأشياء الأكثر استخداما ولكن ليس موضوع آمنة على اتصال قاعدة البيانات وJMSConnection.

وكيف؟

ومثال واحد هو يستخدم إطار الربيع ThreadLocal بشكل كبير لإدارة المعاملات وراء الكواليس عن طريق الحفاظ على هذه الكائنات الاتصال في المتغيرات ThreadLocal. على مستوى عال، عند بدء صفقة يحصل الاتصال (وتعطيل السيارات ارتكاب) ويحفظه في ThreadLocal. على المزيد من المكالمات ديسيبل أنه يستخدم نفس اتصال للتواصل مع ديسيبل. في النهاية، فإنه يأخذ اتصال من ThreadLocal ويرتكب (أو العودة) الصفقة والافراج عن الاتصال.

وأعتقد log4j يستخدم أيضا ThreadLocal للحفاظ على MDC.

وThreadLocal هو مفيد، عندما كنت تريد أن يكون بعض الدول التي لا ينبغي أن تكون مشتركة بين المواضيع المختلفة، ولكن ينبغي أن يكون الوصول إليها من كل موضوع خلال فترة بقائه كله.

وكمثال على ذلك، تخيل تطبيق ويب، حيث يتم تقديم كل طلب من موضوع مختلف. تخيل أن لطلب كل ما تحتاجه قطعة من البيانات عدة مرات، وهو أمر مكلف جدا لحساب. مع ذلك، أن البيانات قد تغيرت لكل طلب وارد، وهو ما يعني أنه لا يمكنك استخدام مخبأ عادي. ومن شأن حل سريع بسيط لهذه المشكلة يكون لديك على وصول عقد متغير ThreadLocal لهذه البيانات، بحيث يكون لديك لحساب ذلك مرة واحدة فقط لكل طلب. بطبيعة الحال، يمكن أيضا أن تحل هذه المشكلة دون استخدام ThreadLocal، ولكن أنا وضعت لأغراض التوضيح.

وقال ذلك، لدينا في الاعتبار أن ThreadLocals هي في جوهرها شكل من أشكال الدولة العالمية. ونتيجة لذلك، فإنه يحتوي على العديد من الآثار الأخرى، وينبغي ألا تستخدم إلا بعد النظر في جميع الحلول الممكنة الأخرى.

لا جديد حقا هنا، لكنني اكتشفت اليوم أن ThreadLocal أمر مفيد للغاية عند استخدام فول التحقق في تطبيق ويب. يتم ترجمة رسائل التحقق من الصحة، ولكن عن طريق استخدام Locale.getDefault() الافتراضية. يمكنك تكوين Validator مع MessageInterpolator مختلفة، ولكن ليس هناك طريقة لتحديد Locale عند استدعاء validate. لذلك يمكن أن إنشاء ThreadLocal<Locale> ثابت (أو الأفضل من ذلك، وعاء العامة مع الأشياء الأخرى التي قد تحتاج إلى أن تكون ThreadLocal ومن ثم يكون مخصص MessageInterpolator اختيار Locale من ذلك. والخطوة التالية هي لكتابة ServletFilter الذي يستخدم قيمة الجلسة أو request.getLocale() لاختيار لغة وتخزينها في إشارة ThreadLocal الخاص بك.

وكما ذكر من قبلunknown (جوجل)، استخدام انها هو تعريف متغير عمومي فيه قيمة المشار إليها يمكن أن تكون فريدة من نوعها في كل موضوع. انها عادة الأعراف يستلزم تخزين نوع من المعلومات السياقية التي يرتبط موضوع الحالي للتنفيذ.

ونحن استخدامها في بيئة جافا EE لتمرير هوية المستخدم إلى الفئات التي لا جاوة EE علم (لم يكن لديك الوصول إلى HttpSession، أو EJB SessionContext). بهذه الطريقة رمز، مما يجعل استخدام الهوية للعمليات القائمة على الأمن، يمكن الوصول إلى هوية من أي مكان، دون الحاجة لتمرير ذلك صراحة في كل استدعاء الأسلوب.

ودورة الطلب / استجابة للعمليات في معظم يدعو جافا EE يجعل هذا النوع من الاستخدام السهل لأنه يعطي محددة جيدا نقاط الدخول والخروج لوضع وضبطه وThreadLocal.

سيضمن ThreadLocal الوصول إلى الكائن القابل للتغيير بواسطة مؤشرات الترابط المتعددة في الطريقة غير المتزامنة ، مما يعني جعل الكائن القابل للتغيير غير قابل للتغيير داخل الطريقة.

يتم تحقيق ذلك من خلال إعطاء مثيل جديد للكائن القابل للتغيير لكل مؤشر ترابط حاول الوصول إليه.لذا فهي نسخة محلية لكل موضوع.هذا هو بعض الاختراق على جعل متغير مثيل في طريقة يمكن الوصول إليها مثل متغير محلي.كما علمت أن المتغير المحلي متاح فقط للخيط ، هناك اختلاف واحد ؛الطريقة لن تتوفر المتغيرات المحلية للمعلومات بمجرد انتهاء تنفيذ الطريقة حيث سيكون الكائن القابل للتغيير مع ThreadLocal متاحًا عبر طرق متعددة حتى نقوم بتنظيفه.

حسب التعريف:

تمكنك فئة ThreadLocal في Java من إنشاء متغيرات لا يمكن قراءتها إلا من قبل نفس الخيط.وبالتالي ، حتى إذا قام اثنين من موضوعين بتنفيذ نفس الرمز ، ولديه الرمز مرجع إلى متغير مؤشر ترابط ، فإن الخيطين لا يمكن أن يروا متغيرات Threadlocal لبعضهما البعض.

كل Thread في جافا يحتوي على ThreadLocalMap فيه.
أين

Key = One ThreadLocal object shared across threads.
value = Mutable object which has to be used synchronously, this will be instantiated for each thread.

تحقيق ThreadLocal:

الآن قم بإنشاء فئة مجمعة لـ ThreadLocal والتي ستحتفظ بالكائن القابل للتغيير كما هو موضح أدناه (مع أو بدون initialValue()).
الآن سوف يعمل برنامج getter وsetter لهذا المجمع على مثيل Threadlocal بدلاً من الكائن القابل للتغيير.

إذا لم يجد getter() الخاص بـ Threadlocal أي قيمة في خريطة Threadlocalmap الخاصة بـ Thread;ثم سيقوم باستدعاء القيمة الأولية () للحصول على نسخته الخاصة فيما يتعلق بسلسلة الرسائل.

class SimpleDateFormatInstancePerThread {

    private static final ThreadLocal<SimpleDateFormat> dateFormatHolder = new ThreadLocal<SimpleDateFormat>() {

        @Override
        protected SimpleDateFormat initialValue() {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd") {
                UUID id = UUID.randomUUID();
                @Override
                public String toString() {
                    return id.toString();
                };
            };
            System.out.println("Creating SimpleDateFormat instance " + dateFormat +" for Thread : " + Thread.currentThread().getName());
            return dateFormat;
        }
    };

    /*
     * Every time there is a call for DateFormat, ThreadLocal will return calling
     * Thread's copy of SimpleDateFormat
     */
    public static DateFormat getDateFormatter() {
        return dateFormatHolder.get();
    }

    public static void cleanup() {
        dateFormatHolder.remove();
    }
}

الآن wrapper.getDateFormatter() سوف اتصل threadlocal.get() والتي سوف تحقق currentThread.threadLocalMap يتضمن هذا (مؤشر الترابط المحلي) مثيل.
إذا كانت الإجابة بنعم، فقم بإرجاع القيمة (SimpleDateFormat) لمثيل Threadlocal المقابل
وإلا أضف الخريطة باستخدام مثيل Threadlocal هذا، originalValue().

طيه يتم تحقيق سلامة الخيط في هذه الفئة القابلة للتغيير؛بواسطة كل مؤشر ترابط يعمل مع مثيله القابل للتغيير ولكن مع نفس مثيل ThreadLocal.يعني أن جميع مؤشرات الترابط ستشارك نفس مثيل ThreadLocal كمفتاح، ولكن مثيل SimpleDateFormat مختلف كقيمة.

https://github.com/skanagavelu/yt.tech/blob/master/src/ThreadLocalTest.java

وغالبا ما تستخدم

والمتغيرات المحلية الموضوع لمنع مشاركة في التصاميم على أساس سنغلتونس قابلة للتغيير أو المتغيرات العالمية.

ويمكن استخدامه في سيناريوهات مثل صنع اتصال JDBC منفصلة لكل موضوع عندما كنت لا تستخدم تجمع اتصال.

private static ThreadLocal<Connection> connectionHolder
           = new ThreadLocal<Connection>() {
      public Connection initialValue() {
           return DriverManager.getConnection(DB_URL);
          }
     };

public static Connection getConnection() {
      return connectionHolder.get();
} 

عند استدعاء getConnection، فإنه سيعود اتصال المرتبطة بهذا thread.The نفسه يمكن القيام به مع خصائص أخرى مثل dateformat، سياق المعاملة التي كنت لا ترغب في مشاركة بين المواضيع.

وأنت يمكن أن تستخدم أيضا المتغيرات المحلية لنفسه، ولكن هذه الموارد وعادة ما تستغرق وقتا في الخلق، لذلك كنت لا تريد إنشاء لهم مرارا وتكرارا كلما قمت بإجراء بعض منطق التعامل معهم. ومع ذلك، يتم تخزين القيم ThreadLocal في كائن موضوع نفسه وبمجرد أن موضوع جمع القمامة، وولت هذه القيم أيضا.

يفسر استخدام ThreadLocal بشكل جيد للغاية.

ال ThreadLocal تتيح لك الفئة في Java إنشاء متغيرات لا يمكن قراءتها وكتابتها إلا بواسطة نفس الموضوع.وبالتالي، حتى إذا كان هناك خيطان ينفذان نفس الكود، وكان الكود يحتوي على مرجع لمتغير ThreadLocal، فلن يتمكن الخيطان من رؤية متغيرات ThreadLocal لبعضهما البعض.

اقرأ أكثر

و[للإشارة] ThreadLocal لا يمكن أن تحل مشاكل تحديث الكائن المشترك. فمن المستحسن استخدام كائن staticThreadLocal التي يشترك فيها جميع العمليات في نفس الموضوع. يجب أن تنفذ طريقة [إجباري] إزالة () من خلال المتغيرات ThreadLocal، خاصة عند استخدام حمامات موضوع الذي غالبا ما يتم استخدامها المواضيع. خلاف ذلك، قد تؤثر على منطق الأعمال اللاحقة ويسبب مشاكل غير متوقعة مثل تسرب الذاكرة.

والتخزين المؤقت، في وقت ما لديك لحساب الكثير نفس القيمة من الوقت حتى عن طريق تخزين آخر مجموعة من المدخلات إلى الطريقة والنتيجة التي يمكن أن تسرع رمز يصل. باستخدام الموضوع التخزين المحلي على تجنب الاضطرار إلى التفكير في تأمين.

وThreadLocal هو وظيفة توفيرها خصيصا من قبل JVM لتوفير مساحة تخزين معزولة عن المواضيع فقط. مثل قيمة الدرجة راقب متغير لا بد لحظة معينة من فئة فقط. كل كائن له قيمها فقط، وأنها لا يمكن أن نرى كل قيمة أخرى. وذلك هو مفهوم المتغيرات ThreadLocal، فهي المحلي إلى موضوع بمعنى مثيلات الكائن الترابط الأخرى باستثناء تلك التي خلقها، لا يمكن رؤيته. انظر هنا

import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;


public class ThreadId {
private static final AtomicInteger nextId = new AtomicInteger(1000);

// Thread local variable containing each thread's ID
private static final ThreadLocal<Integer> threadId = ThreadLocal.withInitial(() -> nextId.getAndIncrement());


// Returns the current thread's unique ID, assigning it if necessary
public static int get() {
    return threadId.get();
}

public static void main(String[] args) {

    new Thread(() -> IntStream.range(1, 3).forEach(i -> {
        System.out.println(Thread.currentThread().getName() + " >> " + new ThreadId().get());
    })).start();

    new Thread(() -> IntStream.range(1, 3).forEach(i -> {
        System.out.println(Thread.currentThread().getName() + " >> " + new ThreadId().get());
    })).start();

    new Thread(() -> IntStream.range(1, 3).forEach(i -> {
        System.out.println(Thread.currentThread().getName() + " >> " + new ThreadId().get());
    })).start();

}
}

وThreadlocal يوفر وسيلة سهلة للغاية لتحقيق الأشياء إعادة استخدام بتكلفة صفر.

وكان لي الحالة التي تكون فيها مواضيع متعددة تخلق صورة من ذاكرة قابلة للتغيير، على كل إعلام التحديث.

وأنا استخدم Threadlocal على كل موضوع، ومن ثم فإن كل موضوع يحتاج فقط لإعادة الصورة القديمة ثم تحديثه مرة أخرى من ذاكرة التخزين المؤقت على كل إعلام التحديث.

والأجسام القابلة لإعادة الاستخدام المعتادة من برك وجوه لها تكلفة السلامة موضوع المرتبطة بها، في حين أن هذا النهج لا شيء.

هناك 3 سيناريوهات لاستخدام مساعد الطبقة مثل SimpleDateFormat في التعليمات البرمجية ذات مؤشرات الترابط المتعددة، أيهما أفضل للاستخدام ThreadLocal

السيناريوهات

1- باستخدام مثل كائن حصة بمساعدة القفل أو المزامنة الآلية التي تجعل التطبيق بطيء

2- باستخدام ك كائن محلي داخل طريقة

في هذا السيناريو، إذا كان لدينا 4 موضوع كل واحد يدعو طريقة 1000 الوقت ثم لدينا
4000 SimpleDateFormat تم إنشاء الكائن وانتظار GC لمسحها

3- استخدام ThreadLocal

إذا كان لدينا 4 موضوع وأعطينا ل كل موضوع مثيل SimpleDateFormat واحد
اذا لدينا 4 خيوط, 4 كائنات من SimpleDateFormat.

ليست هناك حاجة لآلية القفل وإنشاء الكائنات وتدميرها.(التعقيد الزمني الجيد والتعقيد المكاني)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top