जावा में आपके द्वारा सामना की गई सबसे अधिक समसामयिक समस्या क्या है? [बन्द है]


191

यह जावा में आम समसामयिक समस्याओं के बारे में एक सर्वेक्षण है। एक उदाहरण क्लासिक गतिरोध या दौड़ की स्थिति या शायद स्विंग में EDT थ्रेडिंग कीड़े हो सकता है। मैं दोनों संभावित मुद्दों की चौड़ाई में दिलचस्पी रखता हूं, लेकिन यह भी कि कौन से मुद्दे सबसे आम हैं। तो, कृपया प्रति टिप्पणी एक जावा कंसीलर बग का एक विशिष्ट उत्तर छोड़ दें और यदि आपने जो देखा है, उसे वोट करें।


16
यह बंद क्यों है? यह जावा में अन्य प्रोग्रामर से भीख मांगने के लिए उपयोगी है, और इस बात का अंदाजा लगाने के लिए कि अन्य जावा डेवलपर्स द्वारा संगामिति दोषों के वर्ग को सबसे अधिक देखा जा रहा है।
L --o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e

@Longpoke क्लोजर संदेश बताता है कि यह बंद क्यों है। यह एक विशिष्ट "सही" उत्तर वाला प्रश्न नहीं है, यह एक पोल / सूची प्रश्न से अधिक है। और स्टैक ओवरफ्लो इन प्रकार के प्रश्नों की मेजबानी करने का इरादा नहीं करता है। यदि आप उस नीति से असहमत हैं, तो आप मेटा पर चर्चा कर सकते हैं ।
आंद्रेज डॉयल

7
मुझे लगता है कि समुदाय इस लेख के 100+ विचार / दिन होने से असहमत है! मैंने इसे बहुत उपयोगी पाया है क्योंकि मैं एक स्थिर विश्लेषण उपकरण के विकास से जुड़ा हुआ हूं जो विशेष रूप से समसामयिक मुद्दों पर विचार करने के लिए डिज़ाइन किया गया है । थ्रेडसेफ़ के परीक्षण और सुधार के लिए आम तौर पर सामना की जाने वाली समस्याओं का एक बैंक होना बहुत अच्छा रहा है।
क्रेग मैनसन

जावा कंसीडर के लिए कोड समीक्षा चेकलिस्ट इस प्रश्न के उत्तर में वर्णित अधिकांश कमियों को दिन-प्रतिदिन की कोड समीक्षाओं के लिए सुविधाजनक रूप में पचाता है।
लेवेंटोव

जवाबों:


125

सबसे आम समसामयिक समस्या जो मैंने देखी है, वह यह नहीं समझ रही है कि एक धागे से लिखे गए क्षेत्र को एक अलग धागे द्वारा देखे जाने की गारंटी नहीं है । इसका एक सामान्य अनुप्रयोग:

class MyThread extends Thread {
  private boolean stop = false;

  public void run() {
    while(!stop) {
      doSomeWork();
    }
  }

  public void setStop() {
    this.stop = true;
  }
}

जब तक रोक के रूप में नहीं है अस्थिर या setStopऔर runनहीं कर रहे हैं सिंक्रनाइज़ इस काम के लिए गारंटी नहीं है। यह गलती विशेष रूप से 99.999% के रूप में शैतानी है, यह व्यवहार में कोई फर्क नहीं पड़ेगा क्योंकि पाठक धागा अंततः परिवर्तन देखेंगे - लेकिन हम नहीं जानते कि उसने कितनी जल्दी इसे देखा।


9
इसका एक बड़ा समाधान स्टॉप इंस्टेंस वेरिएबल को AtomicBoolean बनाना है। यह गैर-वाष्पशील की सभी समस्याओं को हल करता है, जबकि आप झामुमो के मुद्दों से बचते हैं।
कर्क वायली

39
यह 'कई मिनटों' से भी बदतर है - आप कभी भी इसे नहीं देख सकते। मेमोरी मॉडल के तहत, JVM को ((रोकें) जबकि (सही) में ऑप्टिमाइज़ करने की अनुमति है और फिर आप hosed हो चुके हैं। यह केवल कुछ सर्वरों पर ही हो सकता है, केवल सर्वर मोड में, जब JVM लूप के x पुनरावृत्तियों के बाद पुन: जुड़ता है, आदि!
कोवन

2
आप परमाणु बूलियन से अधिक परमाणु बूलियन का उपयोग क्यों करना चाहेंगे? मैं संस्करण 1.4+ के लिए विकसित कर रहा हूं, तो क्या केवल अस्थिर घोषित करने के साथ कोई नुकसान है?
पूल

2
निक, मुझे लगता है कि यह है क्योंकि परमाणु कैस आमतौर पर अस्थिर से भी तेज है। 1.4 में अस्थिर रूप में सिंक्रनाइज़ उपयोग करने के लिए 1.4 अपने ही सुरक्षित विकल्प IMHO के लिए विकसित कर रहे हैं के रूप में यह जावा 5 में है मजबूत स्मृति बाधा गारंटी नहीं मिला है
Kutzi

5
@Thomas: जावा मेमोरी मॉडल के कारण। आपको इसके बारे में पढ़ना चाहिए, अगर आप इसे विस्तार से जानना चाहते हैं (ब्रायन गोएट्ज द्वारा जावा कॉनक्यूरेन्सी इन प्रैक्टिस) इसे अच्छा उदाहरण बताते हैं)। संक्षेप में: जब तक आप मेमोरी सिंक्रोनाइज़ेशन कीवर्ड / कंस्ट्रक्शन का उपयोग नहीं करते हैं (जैसे कि वाष्पशील, सिंक्रनाइज़, एटॉमिक एक्सिज़, लेकिन यह भी कि जब एक थ्रेड समाप्त हो जाता है) एक थ्रेड में कोई गारंटी नहीं होती है कि किसी भी फ़ील्ड में किए गए परिवर्तनों को देखने के लिए अलग-अलग थ्रेड
Kutzi

178

मेरी # 1 सबसे दर्दनाक समसामयिक समस्या तब हुई जब दो अलग-अलग खुले स्रोत पुस्तकालयों ने कुछ ऐसा किया:

private static final String LOCK = "LOCK";  // use matching strings 
                                            // in two different libraries

public doSomestuff() {
   synchronized(LOCK) {
       this.work();
   }
}

पहली नज़र में, यह एक बहुत तुच्छ तुल्यकालन उदाहरण जैसा दिखता है। तथापि; क्योंकि स्ट्रिंग्स को जावा में इंटर्न किया "LOCK"जाता है , शाब्दिक स्ट्रिंग एक ही उदाहरण के रूप में निकलता है java.lang.String(भले ही वे एक-दूसरे से पूरी तरह से अलग-अलग घोषित किए गए हों।) परिणाम स्पष्ट रूप से खराब है।


62
यह एक कारण है कि मैं निजी स्थिर अंतिम वस्तु लॉक = नई वस्तु () को क्यों पसंद करता हूं;
आंद्रेज डॉयल

17
मैं इसे प्यार करता हूँ - ओह, यह बुरा है :)
Thorbjørn रेवन एंडरसन

7
यही कारण है कि जावा पहेलियों 2. के लिए एक अच्छा एक है
डोव Wasserman

12
वास्तव में ... यह वास्तव में मुझे चाहता है कि संकलक आपको एक स्ट्रिंग पर सिंक्रनाइज़ करने की अनुमति देने से इनकार कर दे। स्ट्रिंग इंटर्निंग को देखते हुए, ऐसा कोई मामला नहीं है जहां यह "अच्छी बात (टीएम)" होगी।
जारेड

3
@ जारेड: "जब तक स्ट्रिंग को नजरबंद नहीं किया जाता है" कोई मतलब नहीं है। स्ट्रिंग्स जादुई रूप से "इंटर्न" नहीं बनती हैं। String.intern () एक अलग ऑब्जेक्ट लौटाता है, जब तक कि आपके पास पहले से निर्दिष्ट स्ट्रिंग का विहित उदाहरण नहीं है। इसके अलावा, सभी शाब्दिक तार और स्ट्रिंग-मूल्यवान स्थिर अभिव्यक्ति को नजरबंद किया जाता है। हमेशा। JLS के String.intern () और .103.10.5 के लिए डॉक्स देखें।
लॉरेंस गोन्साल्व्स

65

एक क्लासिक समस्या उस वस्तु को बदल रही है जिस पर आप इसे सिंक्रनाइज़ कर रहे हैं:

synchronized(foo) {
  foo = ...
}

अन्य समवर्ती धागे फिर एक अलग वस्तु पर सिंक्रनाइज़ हो रहे हैं और यह ब्लॉक आपके द्वारा अपेक्षित पारस्परिक बहिष्करण प्रदान नहीं करता है।


19
इसके लिए एक आईडीईए निरीक्षण है जिसे "गैर-अंतिम क्षेत्र पर सिंक्रोनाइज़ेशन" उपयोगी शब्दार्थ की संभावना नहीं है। बहुत अच्छा।
जेन एस।

8
हा ... अब यह एक यातनापूर्ण वर्णन है। "उपयोगी शब्दार्थ होने की संभावना नहीं" को "सबसे अधिक संभावित रूप से टूटने" के रूप में वर्णित किया जा सकता है। :)
एलेक्स मिलर

मुझे लगता है कि यह कड़वा जावा था जो इसके ReadWriteLock में था। सौभाग्य से अब हमारे पास java.util.concurrency.locks है, और डग गेंद पर थोड़ा अधिक है।
टॉम हॉल्टिन -

मैंने भी अक्सर इस समस्या को देखा है। केवल अंतिम वस्तुओं पर सिंक करें, उस मामले के लिए। FindBugs एट अल। मदद करो, हाँ।
जिम्पफ

क्या यह केवल असाइनमेंट के दौरान एक समस्या है? (देखें @ एलेक्स मिलर का उदाहरण एक मानचित्र के साथ नीचे है) क्या नक्शे के उदाहरण में भी यही समस्या होगी?
एलेक्स बेयर्डस्ले

50

एक सामान्य समस्या कैलेंडर और SimpleDateFormat जैसे कई थ्रेड्स (अक्सर उन्हें स्थैतिक चर में कैशिंग द्वारा) का उपयोग करके सिंक्रनाइज़ेशन के साथ उपयोग कर रही है। ये कक्षाएं थ्रेड-सुरक्षित नहीं हैं इसलिए बहु-थ्रेडेड पहुंच अंततः असंगत स्थिति के साथ अजीब समस्याएं पैदा करेगी।


क्या आपको इसके किसी संस्करण में इस बग वाले किसी भी ओपन सोर्स प्रोजेक्ट का पता है? मैं वास्तविक दुनिया के सॉफ्टवेयर में इस बग के ठोस उदाहरणों की तलाश कर रहा हूं।
reprogrammer

47

डबल-चेकिंग लॉकिंग। सब मिलाकर।

प्रतिमान, जिसे मैंने बीईए में काम करते समय समस्याओं को सीखना शुरू किया था, यह है कि लोग निम्नलिखित तरीके से एक सिंगलटन की जांच करेंगे:

public Class MySingleton {
  private static MySingleton s_instance;
  public static MySingleton getInstance() {
    if(s_instance == null) {
      synchronized(MySingleton.class) { s_instance = new MySingleton(); }
    }
    return s_instance;
  }
}

यह कभी काम नहीं करता है, क्योंकि एक और धागा सिंक्रनाइज़ेशन ब्लॉक में मिल सकता है और s_instance अब शून्य नहीं है। तो प्राकृतिक परिवर्तन तो इसे बनाने के लिए है:

  public static MySingleton getInstance() {
    if(s_instance == null) {
      synchronized(MySingleton.class) {
        if(s_instance == null) s_instance = new MySingleton();
      }
    }
    return s_instance;
  }

यह या तो काम नहीं करता है, क्योंकि जावा मेमोरी मॉडल इसका समर्थन नहीं करता है। आपको इसे काम करने के लिए s_instance को अस्थिर घोषित करने की आवश्यकता है, और तब भी यह केवल जावा 5 पर काम करता है।

जो लोग जावा मेमोरी मॉडल की पेचीदगियों से परिचित नहीं हैं वे हर समय इसे गड़बड़ करते हैं ।


7
एनम सिंगलटन पैटर्न इन सभी समस्याओं को हल करता है (इस पर जोश बलोच की टिप्पणी देखें)। जावा प्रोग्रामर के बीच इसके अस्तित्व का ज्ञान अधिक व्यापक होना चाहिए।
रॉबिन

मुझे अभी भी एक ही मामले में भागना बाकी है जहां एक सिंगलटन की आलसी शुरुआत वास्तव में उचित थी। और अगर ऐसा है, तो बस विधि को सिंक्रनाइज़ घोषित करें।
डोव वासरमैन

3
यह वही है जो मैं सिंगलटन वर्गों के आलसी प्रारंभिककरण के लिए उपयोग करता हूं। इसके अलावा किसी भी सिंक्रनाइज़ेशन की आवश्यकता नहीं है क्योंकि यह जावा द्वारा अनुमानित है। वर्ग फू {स्थिर वर्ग धारक {स्थिर फू फू = नया फू (); } स्थिर फू getInstance () {रिटर्न होल्डर.फू; }}
इरफान जुल्फिकार

इरफान, जिसे पुघ की विधि कहा जाता है, जो मुझे याद है
क्रिस आर

@ रॉबिन, क्या यह सिर्फ एक स्टैटिक इनिशियलाइज़र का उपयोग करने के लिए सरल नहीं है? जिन्हें हमेशा सिंक्रोनाइज़ करने की गारंटी दी जाती है।
मैट बी

47

विशेष रूप से पुनरावृत्ति या कई कार्यों के दौरान, द्वारा लौटाए गए ऑब्जेक्ट पर ठीक से सिंक्रनाइज़ नहीं Collections.synchronizedXXX()किया जा रहा है:

Map<String, String> map = Collections.synchronizedMap(new HashMap<String, String>());

...

if(!map.containsKey("foo"))
    map.put("foo", "bar");

यह गलत है । एकल संचालन होने के बावजूद synchronized, आह्वान के बीच मानचित्र की स्थिति containsऔर putदूसरे धागे से इसे बदला जा सकता है। यह होना चाहिए:

synchronized(map) {
    if(!map.containsKey("foo"))
        map.put("foo", "bar");
}

या ConcurrentMapकार्यान्वयन के साथ :

map.putIfAbsent("foo", "bar");

5
या बेहतर है, एक समवर्ती HashMap और putIfAbsent का उपयोग करें।
टॉम हॉल्टिन -

37

हालाँकि शायद आप जो पूछ रहे हैं वह ठीक नहीं है, मेरे द्वारा सामना की जाने वाली सबसे अधिक समसामयिक समस्या है (शायद क्योंकि यह सामान्य एकल-थ्रेडेड कोड में आता है) एक है

java.util.ConcurrentModificationException

जैसी चीजों के कारण:

List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));
for (String string : list) { list.remove(string); }

नहीं, यह पूरी तरह से मैं क्या देख रहा हूँ। धन्यवाद!
एलेक्स मिलर

30

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

 List<String> l = Collections.synchronizedList(new ArrayList<String>());
 String[] s = l.toArray(new String[l.size()]);

उदाहरण के लिए, ऊपर की दूसरी पंक्ति में, toArray()और size()विधियाँ दोनों अपने आप में सुरक्षित हैं, लेकिन size()इनका मूल्यांकन अलग से किया जाता है toArray(), और सूची में लॉक इन दो कॉलों के बीच नहीं होता है।

यदि आप इस कोड को किसी अन्य थ्रेड के साथ सूची से आइटम को समाप्‍त रूप से चलाते हैं , तो जल्‍दी या बाद में आप एक नया String[]लौटा देंगे , जो सूची के सभी तत्‍वों को रखने के लिए आवश्‍यक से बड़ा है और पूंछ में अशक्त मान है। यह सोचना आसान है क्योंकि सूची में दो विधि कॉल कोड की एक ही पंक्ति में होती हैं यह किसी भी तरह एक परमाणु संचालन है, लेकिन यह नहीं है।


5
अच्छा उदाहरण। मुझे लगता है कि मैं इसे और अधिक सामान्यतः "परमाणु संचालन की संरचना परमाणु नहीं है" के रूप में चाक करूंगा। (एक और सरल उदाहरण के लिए अस्थिर क्षेत्र ++ देखें)
एलेक्स मिलर

29

सबसे आम बग जो हम देखते हैं कि मैं जहां काम करता हूं, प्रोग्रामर लंबे ऑपरेशन करते हैं, जैसे सर्वर कॉल, ईडीटी पर, कुछ सेकंड के लिए जीयूआई को लॉक करना और ऐप को गैर-जिम्मेदाराना बनाना।


उन जवाबों में से एक जो मैं चाहता हूं कि मैं एक बिंदु के लिए एक से अधिक दे सकता हूं
एपीगा

2
EDT = इवेंट डिस्पैच थ्रेड
mjj1409

28

प्रतीक्षा करना भूल जाना () (या कंडीशन.वाइट ()) एक लूप में, यह जांचना कि वेटिंग कंडीशन वास्तव में सही है। इसके बिना, आप अजीब प्रतीक्षा () वेकअप से बग में चलते हैं। Canonical उपयोग होना चाहिए:

 synchronized (obj) {
     while (<condition does not hold>) {
         obj.wait();
     }
     // do stuff based on condition being true
 }

26

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


हां, और हैंडलर के साथ अब इसे संभालने के लिए अच्छे उपकरण हैं।
एलेक्स मिलर

3
क्या आप ऐसे किसी लेख या संदर्भ की लिंक पोस्ट कर सकते हैं जो इसे अधिक विस्तार से समझाए?
अभिजीत कासनिया

22

जब तक मैंने ब्रायन गोएट्ज़ के साथ एक क्लास ली, मुझे महसूस नहीं हुआ कि getterएक सिंक्रनाइज़ के माध्यम से उत्परिवर्तित एक निजी क्षेत्र के गैर- सिंक्रनाइज़ setterको कभी भी अद्यतन मान वापस करने की गारंटी नहीं है । केवल तभी जब कोई चर दोनों पढ़े और लिखे पर सिंक्रनाइज़ किए गए ब्लॉक द्वारा सुरक्षित होता है , तो आपको चर के नवीनतम मूल्य की गारंटी मिलेगी।

public class SomeClass{
    private Integer thing = 1;

    public synchronized void setThing(Integer thing)
        this.thing = thing;
    }

    /**
     * This may return 1 forever and ever no matter what is set
     * because the read is not synched
     */
    public Integer getThing(){
        return thing;  
    }
}

5
बाद के जेवीएम (1.5 और आगे, मुझे लगता है) में, वाष्पशील का उपयोग ठीक करेगा।
जेम्स स्कैच

2
जरुरी नहीं। अस्थिर आपको नवीनतम मूल्य प्रदान करता है इसलिए यह 1 को हमेशा के लिए वापस आने से रोकता है, लेकिन यह लॉकिंग प्रदान नहीं करता है। इसके करीब है, लेकिन काफी समान नहीं है।
जॉन रसेल

1
@ जॉनरसेल ने सोचा था कि अस्थिर होने से पहले रिश्ते की गारंटी होती है। कि "ताला" नहीं है? "एक वाष्पशील चर (§8.3.1.4) के लिए एक v, किसी भी थ्रेड द्वारा v के बाद के सभी पठन (जहां बाद में तुल्यकालन क्रम के अनुसार परिभाषित किया गया है) के साथ v।
शॉन

15

यह सोचते हुए कि आप सिंगल-थ्रेडेड कोड लिख रहे हैं, लेकिन म्यूटेबल स्टैटिक्स (सिंगललेट्स सहित) का उपयोग कर रहे हैं। जाहिर है कि वे धागे के बीच साझा किए जाएंगे। यह आश्चर्यजनक रूप से अक्सर होता है।


3
हाँ सचमुच! म्यूटेबल स्टैटिक्स थ्रेड कंफर्ट को तोड़ते हैं। हैरानी की बात यह है कि मुझे जेसीआईपी या सीपीजे में इस नुकसान के बारे में कभी कुछ नहीं मिला।
जुलिएन चाटंग

मुझे उम्मीद है कि यह समवर्ती प्रोग्रामिंग कर रहे लोगों के लिए स्पष्ट है। थ्रेड-सेफ्टी की जांच के लिए ग्लोबल स्टेट का पहला स्थान होना चाहिए।
gtrak

1
@ गैरी थिंग है, वे सोच नहीं रहे हैं कि वे समवर्ती प्रोग्रामिंग कर रहे हैं।
टॉम हॉल्टिन -

15

सिंक्रनाइज़ किए गए ब्लॉक के भीतर से महत्वाकांक्षी विधि कॉल नहीं की जानी चाहिए।

डेव रे ने अपने पहले उत्तर में इसे छुआ, और वास्तव में मुझे एक गतिरोध का भी सामना करना पड़ा जिसमें श्रोताओं को एक समन्वित विधि के भीतर से आह्वान करने के तरीके भी थे। मुझे लगता है कि अधिक सामान्य सबक यह है कि विधि कॉल को एक सिंक्रनाइज़ ब्लॉक के भीतर से "जंगली में" नहीं किया जाना चाहिए - आपको यह पता नहीं है कि क्या कॉल लंबे समय तक चलेगा, जिसके परिणामस्वरूप गतिरोध होगा, या जो भी हो।

इस मामले में, और आमतौर पर सामान्य तौर पर, समाधान कोड के एक महत्वपूर्ण निजी अनुभाग की रक्षा के लिए सिंक्रनाइज़ किए गए ब्लॉक के दायरे को कम करना था ।

इसके अलावा, चूंकि अब हम एक सिंक्रनाइज़ किए गए ब्लॉक के बाहर श्रोताओं के संग्रह को एक्सेस कर रहे थे, इसलिए हमने इसे कॉपी-ऑन-राइट कलेक्शन में बदल दिया। या हम केवल संग्रह की एक रक्षात्मक प्रतिलिपि बना सकते थे। इस बिंदु पर, आमतौर पर अज्ञात वस्तुओं के संग्रह को सुरक्षित रूप से एक्सेस करने के लिए विकल्प होते हैं।


13

सबसे हाल ही में कॉनकरी-रिलेटेड बग मैं भाग गया था, जो कि इसके कंस्ट्रक्टर में एक एग्जिक्यूटर सर्विस बनाया गया था, लेकिन जब ऑब्जेक्ट को रेफर नहीं किया गया था, तो इसने एक्सकॉउंडर सर्विस को कभी बंद नहीं किया था। इस प्रकार, कुछ हफ़्तों में, हजारों धागे लीक हो गए, जिससे अंततः सिस्टम क्रैश हो गया। (तकनीकी रूप से, यह दुर्घटनाग्रस्त नहीं हुआ, लेकिन इसने ठीक से काम करना बंद कर दिया, जबकि इसे चलाना जारी रखा।)

तकनीकी रूप से, मुझे लगता है कि यह एक संगामिति समस्या नहीं है, लेकिन यह java.util.concurrency पुस्तकालयों के उपयोग से संबंधित समस्या है।


11

असंतुलित सिंक्रनाइज़ेशन, विशेष रूप से मैप्स के खिलाफ एक काफी सामान्य समस्या प्रतीत होती है। बहुत से लोग मानते हैं कि मैप्स पर सिंक्रोनाइज़ करना (एक समवर्ती नहीं है, लेकिन एक हैशपॉप कहते हैं) और नहीं पर सिंक्रनाइज़ होने के लिए पर्याप्त है। यह फिर से हैश के दौरान एक अनंत लूप को जन्म दे सकता है।

एक ही समस्या (आंशिक तुल्यकालन) कहीं भी हो सकती है जिसे आपने राज्य के साथ साझा किया है और फिर भी लिखता है।


11

मुझे सर्वलेट्स के साथ एक समसामयिक समस्या का सामना करना पड़ा, जब ऐसे परिवर्तनशील क्षेत्र हैं जो प्रत्येक अनुरोध द्वारा व्यवस्थित किए जाएंगे। लेकिन सभी अनुरोधों के लिए केवल एक सर्वलेट-इंस्टेंस है, इसलिए यह एकल उपयोगकर्ता वातावरण में पूरी तरह से काम करता है लेकिन जब एक से अधिक उपयोगकर्ता ने सर्वलेट अप्रत्याशित परिणामों का अनुरोध किया है।

public class MyServlet implements Servlet{
    private Object something;

    public void service(ServletRequest request, ServletResponse response)
        throws ServletException, IOException{
        this.something = request.getAttribute("something");
        doSomething();
    }

    private void doSomething(){
        this.something ...
    }
}

10

एक बग नहीं बल्कि, सबसे खराब पाप एक पुस्तकालय प्रदान कर रहा है जिसे आप अन्य लोगों को उपयोग करने का इरादा रखते हैं, लेकिन यह बताते हुए नहीं कि कौन सी कक्षाएं / विधियाँ धागा-सुरक्षित हैं और किन लोगों को केवल एक ही धागे से बुलाया जाना चाहिए आदि।

अधिक लोगों को गोएट्ज़ की पुस्तक में वर्णित संगोष्ठी एनोटेशन (जैसे @ThreadSafe, @GuardedBy आदि) का उपयोग करना चाहिए।


9

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

EDIT: अलग उत्तर के लिए दूसरा भाग ले जाया गया।


क्या आप अंतिम उत्तर को एक अलग उत्तर में विभाजित कर सकते हैं? आइए इसे 1 प्रति पोस्ट रखें। ये दो बहुत अच्छे हैं।
एलेक्स मिलर

9

एक वर्ग के निर्माता के भीतर एक धागा शुरू करना समस्याग्रस्त है। यदि कक्षा को बढ़ाया जाता है, तो उपवर्ग के कंस्ट्रक्टर को निष्पादित करने से पहले धागा शुरू किया जा सकता है।


8

साझा डेटा संरचनाओं में उत्परिवर्ती कक्षाएं

Thread1:
    Person p = new Person("John");
    sharedMap.put("Key", p);
    assert(p.getName().equals("John");  // sometimes passes, sometimes fails

Thread2:
    Person p = sharedMap.get("Key");
    p.setName("Alfonso");

जब ऐसा होता है, तो कोड कहीं अधिक जटिल है कि यह सरल उदाहरण है। बग को पुनर्प्राप्त करना, खोजना और ठीक करना कठिन है। शायद इससे बचा जा सकता है यदि हम कुछ वर्गों को अपरिवर्तनीय और कुछ डेटा संरचनाओं के रूप में चिह्नित कर सकते हैं, केवल अपरिवर्तनीय वस्तुओं को धारण करने के रूप में।


8

एक स्ट्रिंग शाब्दिक या एक स्ट्रिंग शाब्दिक द्वारा परिभाषित निरंतर पर सिंक्रनाइज़ करना (संभवतः) एक समस्या है क्योंकि स्ट्रिंग शाब्दिक को नजरबंद किया गया है और उसी स्ट्रिंग शाब्दिक का उपयोग करके जेवीएम में किसी और द्वारा साझा किया जाएगा। मुझे पता है कि यह समस्या एप्लिकेशन सर्वर और अन्य "कंटेनर" परिदृश्यों में सामने आई है।

उदाहरण:

private static final String SOMETHING = "foo";

synchronized(SOMETHING) {
   //
}

इस मामले में, लॉक करने के लिए स्ट्रिंग "फू" का उपयोग करने वाला कोई भी उसी लॉक को साझा कर रहा है।


संभावित रूप से यह बंद है। समस्या यह है कि WHEN स्ट्रिंग्स पर शब्दार्थ को अपरिभाषित किया जाता है (या, IMNSHO, अल्पविकसित)। "फू" का एक कंपाइलर-टाइम इंटर्न, एक नेटवर्क इंटरफेस से आने वाला "फू" केवल इंटर्न किया जाता है यदि आप इसे बनाते हैं।
किर्क वायली

सही है, इसलिए मैंने विशेष रूप से शाब्दिक स्ट्रिंग स्थिरांक का उपयोग किया है, जिसे इंटर्न होने की गारंटी है।
एलेक्स मिलर

8

मुझे विश्वास है कि भविष्य में जावा के साथ मुख्य समस्या कंस्ट्रक्टरों के लिए दृश्यता की गारंटी (कमी) होगी। उदाहरण के लिए, यदि आप निम्न वर्ग बनाते हैं

class MyClass {
    public int a = 1;
}

और फिर सिर्फ एक और धागे से MyClass की संपत्ति पढ़ें , JavaClM के कार्यान्वयन और मनोदशा के आधार पर MyClass.a 0 या 1 हो सकता है। आज 'ए' 1 होने की संभावना बहुत अधिक है। लेकिन भविष्य में NUMA मशीनों पर यह अलग हो सकता है। बहुत से लोग इसके बारे में नहीं जानते हैं और मानते हैं कि उन्हें आरंभीकरण चरण के दौरान बहु-थ्रेडिंग की परवाह करने की आवश्यकता नहीं है।


मुझे यह हल्के से आश्चर्यजनक लगता है, लेकिन मुझे पता है कि आप एक स्मार्ट दोस्त टिम हैं इसलिए मैं इसे w / oa संदर्भ लूंगा। :) हालांकि, अगर एक अंतिम था, यह एक चिंता का विषय नहीं होगा, सही? आप निर्माण के दौरान अंतिम फ्रीज शब्दार्थ से बंधे होंगे?
एलेक्स मिलर

मुझे अभी भी झामुमो में ऐसी चीजें मिलती हैं जो मुझे आश्चर्यचकित करती हैं, इसलिए मुझे मुझ पर भरोसा नहीं होगा, लेकिन मुझे इस पर पूरा यकीन है। Cs.umd.edu/~pugh/java/memoryModel/… भी देखें । यदि फ़ील्ड अंतिम था तो यह एक समस्या नहीं होगी, तो यह आरंभीकरण चरण के बाद दिखाई देगा।
टिम जानसन

2
यह केवल एक समस्या है, अगर निर्माण से पहले / समाप्त हो जाने से पहले ताजे बनाए गए उदाहरण का संदर्भ उपयोग में है। उदाहरण के लिए, सार्वजनिक पूल में निर्माण के दौरान वर्ग खुद को पंजीकृत करता है और अन्य धागे इसे एक्सेस करने लगते हैं।
रेनेस

3
MyClass.a स्थिर पहुँच को इंगित करता है, और 'a' MyClass का स्थिर सदस्य नहीं है। इसके अलावा, यह 'रेनेस' के रूप में है, यह केवल एक समस्या है अगर अपूर्ण ऑब्जेक्ट का एक संदर्भ लीक हो गया है, जैसे कि कंस्ट्रक्टर में कुछ बाहरी मानचित्र में 'इस' को जोड़ना।
मार्कस जेवरिंग

7

सबसे गंभीर गलती जो मैं अक्सर करता हूं, वह किसी वस्तु पर सूचित () या प्रतीक्षा () को कॉल करने से पहले सिंक्रनाइज़ करना भूल जाता है।


8
अधिकांश संगामिति समस्याओं के विपरीत, क्या यह आसान नहीं है? कम से कम आपको यहां एक अवैध मॉन्टीनेटरस्टेट अपवाद मिलता है ...
डाकू प्रोग्रामर

शुक्र है कि इसे ढूंढना बहुत आसान है ... लेकिन यह अभी भी एक गंभीर गलती है जो मेरे समय को बर्बाद कर देती है इससे अधिक होना चाहिए :)
डेव रे

7

म्यूटेक्स के रूप में एक स्थानीय "नई वस्तु ()" का उपयोग करना।

synchronized (new Object())
{
    System.out.println("sdfs");
}

यह बेकार है।


2
यह शायद बेकार है, लेकिन सभी में सिंक्रनाइज़ करने का कार्य कुछ दिलचस्प चीजें करता है ... निश्चित रूप से हर बार एक नई वस्तु बनाना पूरी तरह से बेकार है।
TREE

4
यह बेकार नहीं है। यह एक ताला के बिना स्मृति अवरोध है।
डेविड रूसेल

1
@ डेविड: एकमात्र समस्या
जेवीएम

@insighter मुझे लगता है कि आपकी राय साझा की गई है ibm.com/developerworks/java/library/j-jtp10185/index.html मैं मानता हूं कि यह एक मूर्खतापूर्ण बात है, जैसा कि आप नहीं जानते कि आपका ज्ञापन अवरोध कब सिंक्रनाइज़ होगा, मैं बस इशारा कर रहा था कि और अधिक कर रहा था कि कुछ भी नहीं।
डेविड रौसेल

7

एक और आम 'समसामयिकता' मुद्दा सिंक्रनाइज़ कोड का उपयोग करना है जब यह बिल्कुल आवश्यक नहीं है। उदाहरण के लिए, मैं अभी भी प्रोग्रामर का उपयोग करते हुए StringBufferया यहां तक ​​कि java.util.Vector(विधि स्थानीय चर के रूप में) देखता हूं ।


1
यह कोई समस्या नहीं है, लेकिन अनावश्यक है, क्योंकि यह बताता है कि जेवीएम वैश्विक मेमोरी के खिलाफ डेटा को सिंक करता है और इसलिए मल्टी-सीपीस पर बुरी तरह से चल सकता है, यहां तक ​​कि कोई भी समवर्ती फैशन में सिंक्रोनाइज़ेशन ब्लॉक का उपयोग नहीं करता है।
रेनेस

6

एकाधिक ऑब्जेक्ट्स जो लॉक प्रोटेक्टेड होते हैं लेकिन आमतौर पर उत्तराधिकार में एक्सेस किए जाते हैं। हम ऐसे कुछ मामलों में भाग लेते हैं, जहां विभिन्न आदेशों में अलग-अलग कोड द्वारा ताले प्राप्त किए जाते हैं, जिसके परिणामस्वरूप गतिरोध होता है।


5

यह महसूस नहीं करना कि thisएक आंतरिक वर्ग thisबाहरी वर्ग का नहीं है। आमतौर पर एक अनाम आंतरिक वर्ग में जो लागू होता है Runnable। जड़ समस्या यह है कि क्योंकि सिंक्रनाइज़ेशन सभी का हिस्सा Objectहै, प्रभावी रूप से कोई स्थैतिक प्रकार की जाँच नहीं है। मैंने इसे कम से कम दो बार usenet पर देखा है, और यह ब्रायन Goetz'z Java Concurrency प्रैक्टिस में भी दिखाई देता है।

BGGA क्लोजर इससे ग्रस्त नहीं thisहै क्योंकि क्लोजर ( thisबाहरी वर्ग का संदर्भ) के लिए कोई नहीं है । यदि आप गैर- thisवस्तुओं को ताले के रूप में उपयोग करते हैं तो यह इस समस्या और अन्य के आसपास हो जाता है।


3

एक वैश्विक वस्तु का उपयोग जैसे लॉकिंग के लिए एक स्थिर चर।

इससे विवाद के कारण बहुत बुरा प्रदर्शन होता है।


खैर, कभी-कभी, कभी नहीं। अगर यह सिर्फ इतना आसान होगा ...
जिम्पफ

यह मानते हुए कि थ्रेडिंग दी गई समस्या के लिए प्रदर्शन को बढ़ाने में मदद करता है, यह हमेशा एक से अधिक थ्रेड एक्सेस कोड जो लॉक द्वारा संरक्षित होता है, के रूप में प्रदर्शन को नीचा दिखाता है।
कोहरलर्म

3

Honesly? के आगमन से पहले java.util.concurrent, सबसे आम समस्या जो मैं नियमित रूप से चला रहा था, जिसे मैं "थ्रेड-थ्रशिंग" कहता था: ऐसे अनुप्रयोग जो कंसीडर के लिए थ्रेड्स का उपयोग करते हैं, लेकिन उनमें से कई को स्पॉन करते हैं और थ्रैशिंग को समाप्त करते हैं।


क्या आप यह अनुमान लगा रहे हैं कि अब आप अधिक समस्याओं में भाग लेंगे कि java.util.concurrent उपलब्ध है?
आंद्रेज डॉयल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.