7

चलो कहते हैं कि मैं दो धागे इस तरह चल रहा है दो:क्या यह गैर-मानक जावा सिंक्रनाइज़ेशन पैटर्न काम करता है?

  • थ्रेड एक जो गणना करता है एक साझा छवि का पिक्सेल अपडेट करते समय
  • थ्रेड बी समय-समय पर छवि और यह प्रतियां स्क्रीन
को पढ़ता है

थ्रेड ए जल्दी से काम करता है, प्रति सेकंड 1 मिलियन अपडेट कहता है, इसलिए मुझे संदेह है कि लॉक/म्यूटेक्स/मॉनिटर पर अक्सर लॉक और अनलॉक करना बुरा विचार होगा। लेकिन अगर कोई तालाब नहीं है और थ्रेड ए से थ्रेड बी के संबंध में पहले से स्थापित होने का कोई तरीका नहीं है, तो जावा मेमोरी मॉडल (जेएमएम स्पेक) थ्रेड बी द्वारा छवि के किसी भी अपडेट को देखने के लिए बिल्कुल गारंटी नहीं है।

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

class ComputationCanvas extends java.awt.Canvas { 

    private Object lock = new Object(); 
    private int[] pixels = new int[1000000]; 

    public ComputationCanvas() { 
     new Thread(this::runThreadA).start(); 
     new Thread(this::runThreadB).start(); 
    } 

    private void runThreadA() { 
     while (true) { 
      for (1000 steps) { 
       update pixels directly 
       without synchornization 
      } 
      synchronized(lock) {} // Blank 
     } 
    } 

    private void runThreadB() { 
     while (true) { 
      Thread.sleep(100); 
      synchronized(lock) {} // Blank 
      this.repaint(); 
     } 
    } 

    @Override 
    public void paint(Graphics g) { 
     g.drawImage(pixels, 0, 0); 
    } 
} 

इस तरह से सही ढंग से धागा एक से डेटा स्थानांतरित बी थ्रेड के प्रभाव को प्राप्त करने में खाली तुल्यकालन ब्लॉक जोड़ने करता है? या क्या कोई और समाधान है जिसे मैं कल्पना करने में असफल रहा?

+1

परमाणु बुलियन चाल क्यों नहीं करेगा? कुछ भी सिंक्रनाइज़ करने से सिंक्रनाइज़ेशन – efekctive

+3

का काम अभी भी छोड़ देता है क्यों 'अस्थिर' का उपयोग नहीं करते? – shmosel

+0

संभवतः संबंधित: http://stackoverflow.com/questions/17108541/happens-before-relationships-with-volatile-fields-and-synchronized-blocks-in-jav – flakes

उत्तर

1

हाँ यह काम करता है। लेकिन यह बहुत काम करता है।

होता है से पहले ही काम करता है जब लेखक की रिहाई पाठक के अधिग्रहण से पहले होता है। आपका कार्यान्वयन मानता है कि जो कुछ भी आप लिख रहे हैं वह ThreadB से बाद में पढ़ने/अपडेट करने से पहले पूरा हो जाएगा। आपके डेटा को सिंक्रनाइज़ किए जाने पर हर समय फ़्लश करने के कारण प्रदर्शन समस्याओं का कारण बन जाएगा, हालांकि मैं कितनी हद तक निश्चित रूप से नहीं कह सकता। निश्चित रूप से, आपने अपना सिंक्रनाइज़ेशन बेहतर अनाज बनाया है, क्या आपने अभी तक इसका परीक्षण किया है?

एक बेहतर समाधान एक सिंगलटन/स्थानांतरण SPSC (एकल निर्माता/एकल उपभोक्ता) कतार का उपयोग लेखन धागा की वर्तमान स्नैपशॉट को संग्रहीत करने के लिए और जब भी आप अद्यतन का उपयोग हो सकता है।

int[] data = ... 
Queue<int[]> queue = new ... 

// Thread A 
while (true) { 
    for (1000 iterations or so) { 
     ... 
    } 
    queue.add(data); 
} 

// Thread B 
while (true) { 
    int[] snapshot = queue.take(); 
    this.repaint(); 
} 

इस का लाभ यह है कि आप busywait लिए, आप बस ब्लॉक करने के लिए कतार के लिए या अगले लिखने तक इंतजार कर सकते हैं की जरूरत नहीं है है। आप लिख सकते हैं कि आपके पास अपडेट करने का समय नहीं है। आपके लिए डेटा फ्लश की योजना बनाने के लिए आपको मनमाने ढंग से थ्रेड शेड्यूलर पर निर्भर रहने की आवश्यकता नहीं है।

याद रखें कि धागे की सुरक्षित डाटा संरचनाओं धागे के बीच डेटा पारित करने के लिए महान हैं।

संपादित करें: ओह, यह कहना भूल गया कि आपके अपडेट कैसे चलते हैं, आप अपने डेटा को यादृच्छिक लिखने से याद रखने के लिए एक सरणी प्रतिलिपि का उपयोग करना चाहेंगे जो कैश नहीं हैं।

+0

'repaint' कोई पैरामीटर नहीं लेता –

+0

@ डेविड कॉनराड आप सही हैं, नीचे पेंट विधि के बारे में सोच रहे थे। – xTrollxDudex

+0

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

संबंधित मुद्दे