2009-11-30 7 views
10

मेरे पास कुछ जावा कोड है जो एक सत्र विशेषता प्राप्त करता है और सेट करता है:लॉकिंग ऑब्जेक्ट के रूप में request.getSession() का उपयोग करना?

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); 
    } 
} 

उत्तर

3

यह आम तौर पर उस लॉक का उपयोग करने के लिए तैयार होता है जिस पर आपका कोई नियंत्रण नहीं होता है। एक ताला को यथासंभव कसकर स्कॉप्ड किया जाना चाहिए और क्योंकि सत्र वैश्विक वस्तु कम या कम है, यह बिल में फिट नहीं है। java.util.concurrent.locks पैकेज से अलग लॉक का उपयोग करने का प्रयास करें और इसे अपनी कक्षा में दायरा दें।

+0

यह दोबारा जांच ताला नहीं है, यह सिर्फ एक नक्शे में एक मूल्य डाल रहा है कि वह पहले से मौजूद नहीं है। – Yishai

+0

सहमत, इसकी शुरुआत। हटाए गए। – Kevin

+0

लॉक को मेरी कक्षा में स्थैतिक बना देगा (जो एक सर्वलेट नहीं है, लेकिन एक वर्ग जो जेएसपी पेज के भीतर से बनाया गया है) सुनिश्चित करें कि सभी अनुरोध एक ही लॉक पर सिंक्रनाइज़ कर रहे हैं? वर्ग एक JSP पृष्ठ के अंदर बनाई गई है – MCS

1

आपका कोड में कम से कम दो कारणों के लिए काम नहीं करेगा।

1) यदि सत्र मौजूद नहीं है, तो आप आसानी से इसे दो बार एक ही उपयोगकर्ता के लिए बना सकते हैं, और एक बदसूरत रेस स्थिति है।

2) सत्र धागे में एक ही वस्तु नहीं है, तो यह वैसे भी काम नहीं करेगा। सत्र शायद equals() एक ही थ्रेड में उसी सत्र में होगा, लेकिन यह काम नहीं करेगा।

3

सर्वलेट्स के संदर्भ में? Servlets कई प्रक्रियाओं में वितरित किया जा सकता है, इसलिए आप हमेशा एक ही सत्र वस्तु नहीं हो सकता है। इसका एक सारांश यह है कि एक सर्वलेट कंटेनर आपको एक ही प्रक्रिया में एक अलग सत्र वस्तु देने का निर्णय ले सकता है।

IIRC, ब्रायन गोएज़ सही सत्र के साथ काम करने की कठिनाई पर एक दिलचस्प लेख लिखा था।

मेरी सलाह: जितना संभव हो सके सत्रों से साफ़ रहें, और यादृच्छिक वस्तुओं को लॉक न करें (लॉक ऑब्जेक्ट का उपयोग करें जिसका कोई अन्य उद्देश्य नहीं है)।

+2

क्या यह आलेख है: http://www.ibm.com/developerworks/library/j-jtp09238.html? उन्होंने चर्चा की है कि एक सिंक्रनाइज़ ब्लॉक का उपयोग करता है लेकिन लॉक के रूप में उपयोग करने के लिए नहीं। – MCS

+0

मुझे लगता है कि वह इस निष्कर्ष पर आता है कि कोई सुरक्षित लॉक नहीं है। –

3

मैं लेख आपको पोस्ट पर एक नज़र ले लिया। आप सभी को एक साथ सिंक्रनाइज़ कर छोड़ सकते हैं और एक ही दृष्टिकोण ले सकता है लेखक का उपयोग करके किया कि तुलना और सेट सुनिश्चित करें कि आपके डेटा सही है:

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://java.sun.com/javase/6/docs/api/java/util/concurrent/atomic/AtomicReference.html

2

कल्पना की गारंटी नहीं है कि इस सब पर मदद मिलेगी:

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

(यह विशिष्ट कार्यान्वयन के लिए काम कर सकते हैं, लेकिन कोई गारंटी देता है कि यह सभी कंटेनर में काम करेंगे कर रहे हैं।)

सर्वलेट 2.5 MR6 का कहना है:

अनुरोध थ्रेड निष्पादित करने वाले एकाधिक सर्लेट्स एक ही समय में एक ही सत्र ऑब्जेक्ट तक सक्रिय पहुंच हो सकते हैं। कंटेनर को यह सुनिश्चित करना चाहिए कि सत्र गुणों का प्रतिनिधित्व करने वाले आंतरिक डेटा संरचनाओं में हेरफेर थ्रेडसेफ तरीके से किया जाता है। डेवलपर की विशेषता वस्तु वस्तुओं के लिए थ्रेडसेफ पहुंच की ज़िम्मेदारी है।यह समवर्ती उपयोग से HttpSession ऑब्जेक्ट के अंदर विशेषता संग्रह की रक्षा, कि संग्रह पैदा करने के लिए दूषित हो करने के लिए एक आवेदन के लिए अवसर को नष्ट करेगा।

असल में, यह कल्पना आपकी समस्या बनाती है। आपका समाधान आपके एप्लिकेशन डिज़ाइन और तैनाती योजना के अनुरूप होना होगा। मुझे यकीन नहीं है कि समस्या का वैश्विक समाधान है जो सभी मामलों में काम करेगा; हालांकि, यदि आप अपने आवेदन के आर्किटेक्चर और आपके एप्लिकेशन सर्वर की कॉन्फ़िगरेशन के बारे में अधिक विशिष्ट हैं तो आपको एक बेहतर उत्तर मिल सकता है।

1

आपको session.setAttribute() थ्रेड से सुरक्षित होने की आवश्यकता नहीं है (ऊपर @McDowell से सर्वलेट spec टिप्पणी देखें)।

हालांकि, के लिए एक अलग उदाहरण का उपयोग करते हैं। मान लीजिए कि आप विशेषता के मान chek करना चाहता था चलो, अगर < = 100 इस मामले में आप getAttribute() तुलना < = 100 और setAttribute() के लिए कोड के ब्लॉक syncronize करने के लिए की आवश्यकता होगी तो इसे अद्यतन करें।

अब, क्या आप लॉक के लिए इस्तेमाल करना चाहिए? याद रखें कि लॉक के लिए अलग-अलग ऑब्जेक्ट्स का उपयोग होने पर कोई सिंक्रनाइज़ेशन नहीं होता है। तो अलग-अलग कोड ब्लॉक को एक ही ऑब्जेक्ट का उपयोग करना चाहिए। session ऑब्जेक्ट की आपकी पसंद ठीक हो सकती है। यह भी याद रखें कि अलग-अलग कोड ब्लॉक सत्र (दोनों पढ़ने/लिखने) तक पहुंच सकते हैं भले ही आपने लॉक लिया हो, जब तक कि अन्य कोड सत्र ऑब्जेक्ट पर भी लॉक न हो। यहां एक गड़बड़ी यह है कि आपके कोड में बहुत से स्थान सत्र ऑब्जेक्ट पर लॉक लेते हैं और इस प्रकार प्रतीक्षा करनी होती है। उदाहरण के लिए, यदि आपका कोड ब्लॉक सत्र विशेषता एक का उपयोग करता है और कोड का एक और हंक सत्र का श्रेय बी का उपयोग करता है, यह अच्छा नहीं अगर वे दोनों सत्र वस्तु पर एक ताला लेने के द्वारा एक दूसरे पर इंतजार की जरूरत नहीं थी होगा। लॉकफोरा नामक स्थैतिक वस्तुओं का उपयोग, और लॉकफ़ोरबी आपके कोड का उपयोग करने के लिए बेहतर विकल्प हो सकता है - उदा। synchronized (LockForA) { }.

0

मुझे एक ही समस्या थी और मैं इसे अपनी कक्षा में गुंजाइश नहीं करना चाहता था क्योंकि मेरी वस्तु का निर्माण दूसरे सत्रों के दूसरे और स्टाल थ्रेड ले सकता है जहां ऑब्जेक्ट पहले से बनाया गया था। मैं सिंक्रनाइज़ करने के अनुरोध के सत्र ऑब्जेक्ट का उपयोग नहीं करना चाहता था क्योंकि एप्लिकेशन सर्वर कार्यान्वयन अलग-अलग अनुरोधों में एक अलग सत्र मुखौटा वापस कर सकता है और विभिन्न ऑब्जेक्ट्स पर सिंक्रनाइज़ करना बस काम नहीं करता है। इसलिए मैं लॉक के रूप में उपयोग करने के लिए सत्र पर ऑब्जेक्ट डालना चुनता हूं और लॉक केवल एक बार बनाया गया सुनिश्चित करने के लिए डबल चेक मुहावरे का उपयोग करता हूं। 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); 
    } 
}