سؤال

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

static class DateTimeFormatter {
    private static final ThreadLocal<SimpleDateFormat> DATE_PARSER_THREAD_LOCAL = new ThreadLocal<SimpleDateFormat>() {
        protected SimpleDateFormat initialValue() {
            return new SimpleDateFormat("yyyy/MM/dd HH:mmz");
        }
    };
    public String format(final Date date) {
        return DATE_PARSER_THREAD_LOCAL.get().format(date);
    }
    public Date parse(final String date) throws ParseException
    {
      return DATE_PARSER_THREAD_LOCAL.get().parse(date);
    }
}
هل كانت مفيدة؟

المحلول

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

وبالإضافة إلى ذلك، يتم تخزين القيم ThreadLocal فعلا في Thread. إذا مات موضوع، يتم جمع كافة القيم المرتبطة بهذا الموضوع من خلال ThreadLocal.

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


تحديث:. المشكلة المذكورة لا يأتي إلا في اللعب عندما تكون القيمة المخزنة في ThreadLocal يحيل الى بشدة أن ThreadLocal-النوع من مرجع دائري

في هذه الحالة، فإن قيمة (أ SimpleDateFormat)، ومرجع لا إلى الوراء إلى ThreadLocal. ليس هناك تسرب للذاكرة في هذا القانون.

نصائح أخرى

انا التخمين كنت القفز من خلال هذه الأطواق منذ SimpleDateFormat هو لا مؤشر الترابط-الآمن.

بينما أنا على علم أنني لست حل المشكلة أعلاه ، يمكن أن أقترح عليك أن ننظر في Joda بالنسبة تاريخ/وقت العمل ؟ Joda لديه مؤشر الترابط-الآمن التاريخ/الوقت آلية التنسيق.لن تكون إضاعة الوقت في تعلم Joda API ايضا, كما انها مؤسسة المعيار الجديد التاريخ/الوقت API الاقتراح.

وهناك <م> لا ينبغي أن أن تكون مثل هذه المشكلة.

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

وهكذا سواء كنت قد وجدت خلل حقيقي ويجب الإبلاغ عن ذلك، أو كنت تفعل شيئا آخر غير صحيح!

أنا أدرك أن هذا ليس بدقة إجابة على سؤالك ولكن كقاعدة عامة أنا لن أقترح استخدام ThreadLocal في situration لا يوجد فيها واضحة هدم في نهاية الطلب/التفاعل.الكلاسيكية هي تفعل هذا النوع من الشيء في حاوية بريمج, للوهلة الأولى يبدو على ما يرام, ولكن منذ المواضيع المجمعة يصبح مشكلة مع ThreadLocal معلقة على الموارد حتى بعد كل طلب تم تجهيزها.

الاقتراحات:

  1. استخدام عامل تصفية مماثلة المجمع لكل تفاعل واضح ThreadLocal في نهاية كل التفاعل
  2. هل يمكن استخدام بديل SimpleDateFormat مثل FastDateFormat من العموم لانج أو Joda شخص قد اقترح
  3. مجرد خلق جديد SimpleDateFormat في كل مرة كنت في حاجة إليها.يبدو الإسراف أعلم ، ولكن في معظم التطبيقات انك لن تلاحظ الفرق

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

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

في المثال الخاص بك ينبغي أن يكون هناك أي مشكلة باستخدام ThreadLocal على الإطلاق.

موضوع المحليين (ووحدانية أيضا!) تصبح مشكلة عندما الخيط السكان المحليين يتم تعيين الحالات تحميلها من قبل classloader أن تفرغ في وقت لاحق.حالة نموذجية في بريمج الحاوية (مثل هر):

  1. Webapp مجموعة الصفحات المحلية أثناء معالجة الطلب.
  2. موضوع يدار من قبل الحاوية.
  3. Webapp ينبغي undeployed.
  4. Classloader webapp لا يمكن garbaged ، لأن هناك إشارة إلى اليسار:من الخيط المحلية على سبيل المثال إلى الدرجة إلى classloader.

نفس الشيء مع وحدانية (جافا.sql.DriverManger و JDBC التي تقدمها webapp).

لذا تجنب مثل هذه الأشياء لا سيما في بيئات تحت السيطرة الكاملة الخاصة بك!

وتنظيف موضوع المحلي بعد استخدامه، إضافة فلتر بريمج للقيام بذلك:

protected ThreadLocal myThreadLocal = new ThreadLocal();

public void doFilter (ServletRequest req, ServletResponse res, chain) throws IOException, ServletException {
    try {
        // Set ThreadLocal (eg. to store heavy computation result done only once per request)
        myThreadLocal.set(context());

        chain.doFilter(req, res);
    } finally {
        // Important : cleanup ThreaLocal to prevent memory leak
        userIsSmartTL.remove();
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top