जावा में एक वर्ग के विभिन्न उदाहरणों को चलाने वाले थ्रेड्स के बीच एक स्थिर चर को कैसे सिंक्रनाइज़ किया जाए?


120

मुझे पता है कि synchronizeकिसी विधि से पहले कीवर्ड का उपयोग करने से उस ऑब्जेक्ट में सिंक्रनाइज़ेशन आता है। यही है, ऑब्जेक्ट के एक ही उदाहरण को चलाने वाले 2 धागे सिंक्रनाइज़ किए जाएंगे।

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

क्या हम निम्नलिखित तरीके से सिंक्रोनाइज़ेशन प्राप्त कर सकते हैं?

public class Test  
{  
   private static int count = 0;  
   private static final Object lock= new Object();    
   public synchronized void foo() 
  {  
      synchronized(lock)
     {  
         count++;  
     }  
  }  
}

क्या यह सच है कि चूंकि हमने एक ऐसी वस्तु को परिभाषित किया है जो lockस्थिर है और हम synchronizedउस लॉक के लिए कीवर्ड का उपयोग कर रहे हैं , इसलिए स्थिर चर countअब कक्षा के उदाहरणों में सिंक्रनाइज़ किया गया है Test?


4
जब तक लॉक ऑब्जेक्ट को अंतिम घोषित नहीं किया जाता है, तब तक ये सभी उत्तर USELESS होते हैं!

इसके अलावा java.util.concurrent.atomic.AtomicInteger
RoundSparrow Hilltx

जवाबों:


193

स्थैतिक चर तक पहुंच को सिंक्रनाइज़ करने के कई तरीके हैं।

  1. एक सिंक्रनाइज़ स्थिर विधि का उपयोग करें। यह क्लास ऑब्जेक्ट पर सिंक्रोनाइज़ करता है।

    public class Test {
        private static int count = 0;
    
        public static synchronized void incrementCount() {
            count++;
        }
    } 
    
  2. स्पष्ट रूप से वर्ग वस्तु पर सिंक्रनाइज़ करें।

    public class Test {
        private static int count = 0;
    
        public void incrementCount() {
            synchronized (Test.class) {
                count++;
            }
        }
    } 
    
  3. किसी अन्य स्थिर वस्तु पर सिंक्रनाइज़ करें।

    public class Test {
        private static int count = 0;
        private static final Object countLock = new Object();
    
        public void incrementCount() {
            synchronized (countLock) {
                count++;
            }
        }
    } 
    

विधि 3 कई मामलों में सर्वश्रेष्ठ है क्योंकि लॉक ऑब्जेक्ट आपके वर्ग के बाहर उजागर नहीं होता है।


1
1. पहले एक भी एक ताला वस्तु की जरूरत नहीं है, यह सबसे अच्छा नहीं होना चाहिए?
बैयान हुआंग जूल

4
2. घोषणा की गणना अस्थिर के रूप में भी काम करेगी, क्योंकि अस्थिर यह सुनिश्चित करता है कि चर सिंक्रनाइज़ किया गया है।
बैयान हुआंग

9
# 3 कारण सबसे अच्छा है कि किसी भी यादृच्छिक बिट पर कोड सिंक्रनाइज़ हो सकता है Test.classऔर संभवतः आपका दिन खराब कर सकता है। इसके अलावा, क्लास इनिशियलाइज़ेशन क्लास में रखे गए लॉक के साथ चलता है, इसलिए यदि आपको क्रेज़ी क्लास इनिशियलाइज़र मिल गए हैं तो आप खुद को सिरदर्द दे सकते हैं। volatileइसके लिए मदद नहीं करता है count++क्योंकि यह एक पढ़ने / संशोधित / लिखने का क्रम है। जैसा कि एक अलग जवाब में उल्लेख किया गया है, java.util.concurrent.atomic.AtomicIntegerसंभावना है कि यहां सही विकल्प है।
fadden

4
यदि आप अन्य थ्रेड्स द्वारा निर्धारित सही मान पढ़ना चाहते हैं, तो गिनती पर रीड ऑपरेशन को सिंक्रनाइज़ करना न भूलें। इसे अस्थिर (घोषणात्मक लेखन के अलावा) घोषित करने से भी मदद मिलेगी।
n0rm1e

1
@Ferrybig नहीं, आप पर ताला लगा रहे हैं Test.classthisसिंक्रनाइज़ गैर-स्थिर विधियों के लिए लॉक होगा
user3237736

64

यदि आप केवल एक काउंटर साझा कर रहे हैं, तो एक परमाणुइंटर या किसी अन्य उपयुक्त वर्ग का उपयोग करने पर विचार करें java.util.concurrent.atomic पैकेज से:

public class Test {

    private final static AtomicInteger count = new AtomicInteger(0); 

    public void foo() {  
        count.incrementAndGet();
    }  
}

3
यह जावा 1.5 में उपलब्ध है, 1.6 में नहीं।
पावेल नोव

4

हाँ यह सच है।

यदि आप अपनी कक्षा के दो उदाहरण बनाते हैं

Test t1 = new Test();
Test t2 = new Test();

फिर t1.foo और t2.foo दोनों एक ही स्थिर ऑब्जेक्ट पर सिंक्रनाइज़ होते हैं और इसलिए एक दूसरे को ब्लॉक करते हैं।


एक दूसरे को ब्लॉक करेगा, एक दूसरे को एक बार में नहीं लेगा अगर ध्यान रखा जाए।
जफ़र अली

0

आप अपने कोड को कक्षा में सिंक्रनाइज़ कर सकते हैं। यह सबसे सरल होगा।

   public class Test  
    {  
       private static int count = 0;  
       private static final Object lock= new Object();    
       public synchronized void foo() 
      {  
          synchronized(Test.class)
         {  
             count++;  
         }  
      }  
    }

आशा है कि आपको यह उत्तर उपयोगी लगेगा।


2
यह काम करेगा, लेकिन जैसा कि @ Fadden द्वारा कहीं और उल्लेख किया गया है, सावधान रहें कि कोई अन्य धागा भी Test.classव्यवहार को सिंक्रनाइज़ और प्रभावित कर सकता है। यही कारण है कि सिंक्रनाइज़ेशन को lockप्राथमिकता दी जा सकती है।
sbk

आप जो कह रहे हैं वह सही है। इसलिए मैं स्पष्ट रूप से उल्लेख करता हूं कि उपरोक्त सबसे सरल तरीका है।
जाफर अली

0

हम स्थैतिक चर के लिए तुल्यकालन को प्राप्त करने के लिए ReentrantLock का भी उपयोग कर सकते हैं ।

public class Test {

    private static int count = 0;
    private static final ReentrantLock reentrantLock = new ReentrantLock(); 
    public void foo() {  
        reentrantLock.lock();
        count = count + 1;
        reentrantLock.unlock();
    }  
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.