سؤال

ولدي بعض رمز جافا الذي يحصل ويضع سمة الدورة:

Object obj = session.getAttribute(TEST_ATTR);
if (obj==null) {
  obj = new MyObject();
  session.setAttribute(obj);
}

في أجل جعل هذا الرمز ذات ألوان، أود أن ألفه في كتلة متزامنة. ولكن ما يمكنني استخدام ككائن قفل؟ هل يعقل أن استخدام الدورة؟

synchronized (session) {
  Object obj = session.getAttribute(TEST_ATTR);
  if (obj==null) {
    obj = new MyObject();
    session.setAttribute(obj);
  }
}
هل كانت مفيدة؟

المحلول

ووعبس عموما على استخدام قفل أن لديك أي سيطرة على. يجب راقب القفل بإحكام ممكن، ومنذ الدورة هي أكثر أو أقل كائن العالمي، فإنه لا تتلاءم مع القانون. محاولة استخدام قفل منفصل عن في java.util.concurrent.locks حزمة ونطاق لصفك.

نصائح أخرى

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

وIIRC، كتب بريان غوتز مادة مثيرة للاهتمام على صعوبة القيام الأمور في نصابها الصحيح مع الدورات.

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

.

وأخذت نظرة على المقال الذي نشر. هل يمكن تخطي مزامنة كل ذلك معا واتخاذ نفس النهج إلى أن مقدم البلاغ لم باستخدام مقارنة وبين مجموعة للتأكد من أن البيانات الخاص بك هو الصحيح:

ServletContext ctx = getServletConfig().getServletContext();
AtomicReference<TYPE> holder 
    = (AtomicReference<TYPE>) ctx.getAttribute(TEST_ATTR);
while (true) {
    TYPE oldVal = holder.get();
    TYPE newVal = computeNewVal(oldVal);
    if (holder.compareAndSet(oldVal, newVal))
        break;
} 

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

HTTP: // جافا .sun.com / javase / 6 / مستندات / المعهد / جافا / UTIL / المتزامنة / الذري / AtomicReference.html

ووالمواصفات لا يضمن أن هذا سيساعد على الإطلاق:

synchronized (session) {
  Object obj = session.getAttribute(TEST_ATTR);
  if (obj==null) {
    obj = new MyObject();
    session.setAttribute(obj);
  }
}

(قد عمل من أجل تطبيقات محددة، ولكن لا توجد ضمانات أنها ستعمل في كافة الحاويات.)

وبريمج 2.5 MR6 يقول:

<اقتباس فقرة>   

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

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

سوف

والتعليمات البرمجية الخاصة بك لا تعمل لسببين على الأقل.

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

2) إذا الدورة ليست هي نفس الكائن في المواضيع، ثم انها لن تعمل على أي حال. من المحتمل أن equals() الدورة إلى الدورة نفسها في موضوع آخر، ولكن ذلك لن ينجح.

وأنت لست بحاجة لقفل منذ session.setAttribute() هو موضوع الآمن (انظر بريمج المواصفات تعليق منMcDowell أعلاه).

ولكن، دعونا استخدام مثال آخر. دعنا نقول أردت تشيك قيمة السمة، ثم تحديثه إذا <= 100. وفي هذه الحالة قد تحتاج إلى syncronize كتلة من التعليمات البرمجية لgetAttribute() للمقارنة <= 100 وsetAttribute().

والآن، ماذا يجب عليك استخدام لقفل؟ تذكر لا يوجد syncronization إذا تم استخدام كائنات مختلفة لقفل. لذا كتل التعليمات البرمجية مختلفة يجب استخدام نفس الكائن. اختيارك من وجوه session قد يكون على ما يرام. تذكر كتل التعليمات البرمجية أيضا أن المختلفة قد الوصول إلى الدورة (من القراءة / الكتابة) حتى لو كنت قد اتخذت قفل، إلا بتأمين هذا الرمز الآخر أيضا على الكائن الدورة. A شرك هنا هو أن العديد من الأماكن في التعليمات البرمجية تأخذ تأمين على كائن جلسة عمل، وبالتالي يجب أن تنتظر. على سبيل المثال، إذا كتلة التعليمات البرمجية يستخدم جلسة السمة ألف وقطعة كبيرة أخرى من التعليمات البرمجية يستخدم جلسة السمة B، سيكون من الجميل لو لم تكن في حاجة إلى الانتظار على بعضها البعض من قبل كل من أخذ تأمين على كائن جلسة عمل. استخدام الأجسام الساكنة اسمه LockForA، وLockForB قد يكون أفضل الخيارات للالتعليمات البرمجية لاستخدام - على سبيل المثال synchronized (LockForA) { }.

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

Object lock = session.getAttribute("SessionLock");
if (lock == null) {
  synchronized (MyObject.class) {
    lock = session.getAttribute("SessionLock");
    if(lock == null) {
      lock = new Object();
      session.setAttribute("SessionLock", lock);
    }
  }
}
synchronized (lock) {
  Object obj = session.getAttribute(TEST_ATTR);
  if (obj==null) {
    obj = new MyObject();
    session.setAttribute(obj);
  }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top