2011-01-25 18 views
6

क्या किसी प्रकार का संदर्भ लागू करने का कोई तरीका है जिसका मूल्य किसी अन्य के साथ आदान-प्रदान किया जा सकता है?परमाणु संदर्भ बनाने के लिए संभव है जिसे परमाणु रूप से बदला जा सकता है?


जावा में हम AtomicReference जो एक स्थानीय चर के साथ बदली जा सकती है, लेकिन एक और AtomicReference साथ नहीं है।

आप कर सकते हैं:

AtomicReference r1 = new AtomicReference("hello"); 
AtomicReference r2 = new AtomicReference("world"); 

और उन्हें दो आपरेशन के संयोजन के साथ स्वैप:

r1.set(r2.getAndSet(r1.get())); 

लेकिन इस बीच, जहां दोनों "hello" शामिल में एक असंगत स्थिति में उन्हें छोड़ देता है। इसके अलावा यदि आप उन्हें परमाणु रूप से स्वैप कर सकते हैं, तो भी आप उन्हें (एक जोड़ी के रूप में) परमाणु रूप से पढ़ नहीं पाए।


मैं ऐसा करने में सक्षम होना चाहते हैं क्या है:

PairableAtomicReference r1 = new PairableAtomicReference("hello"); 
PairableAtomicReference r2 = new PairableAtomicReference("world"); 
AtomicRefPair rp = new AtomicRefPair(r1, r2); 

तो

Object[] oldVal, newVal; 
do { 
    oldVal = rp.get(); 
    newVal = new Object[] {oldVal[1], oldVal[0]}; 
} while (! rp.compareAndSet(oldVal, newVal)); 

मूल्यों स्वैप करने के लिए, और एक अन्य सूत्र में:

AtomicRefPair otherRP = new AtomicRefPair(r1, r2); 
System.out.println(Arrays.toString(otherRP.get())); 

और सुनिश्चित करें कि आउटपुट या तोहोगाया [world, hello]

नोट्स:

  • r1 और r2 इस कार्रवाई के लिए जोड़ा जाता है, लेकिन यह संभव है कि एक और धागा स्वतंत्र रूप से युग्मित हो जाएगा है, कहते हैं कि r1 और एक अन्य r3
  • वहाँ (दुर्भाग्य से इसका मतलब है कि मैं this solution उपयोग नहीं कर सकते।) इन संदर्भों में से सैकड़ों हजारों होंगे, इसलिए वैश्विक ReentrantLock एक बड़ी बाधा होगी।
  • rp और otherRP आवश्यक रूप से धागे के बीच साझा नहीं किए जाते हैं, इसलिए बस उन्हें लॉक करना काम नहीं करेगा। वे interned हो सकते हैं, लेकिन इंटर्न पूल को अपने सिंक्रनाइज़ेशन की आवश्यकता होगी जो एक और बाधा होगी।
  • मैंने केवल 2 संदर्भों के समूह बनाए हैं, लेकिन 3 या उससे अधिक समूह बनाने की क्षमता बोनस होगी।

क्या AtomicRefPair का लॉक-मुक्त संस्करण लागू करना संभव है? मेरे पास एक झुकाव है कि यह नहीं है, लेकिन यदि नहीं तो शायद वहां कोई लेख है जो बताता है क्यों?


संबंधित: How do I atomically swap 2 ints in C#?

+1

अमरूद में एक Interner, जो ConcurrentHashMap का उपयोग करता है, इसलिए विवाद औसतन मनमाने ढंग से छोटे हो सकता है। – maaartinus

उत्तर

3

मैं वहाँ एक अच्छा समाधान है, लेकिन निम्नलिखित बदसूरत एक काम कर सकता है, तो पता नहीं है:

public final class MyReference<T> extends ReentrantLock implements Comparable<MyReference<T>> { 
    public MyReference() { 
     id = counter.incrementAndGet(); 
    } 

    public void swap(MyReference<T> other) { 
     if (id < other.id) { 
      lock(); 
      other.lock(); 
     } else { 
      other.lock(); 
      lock(); 
     } 
     final T tmp = value; 
     value = other.value; 
     other.value = tmp; 
     unlock(); 
     other.unlock(); 
    } 

    public static <T> List<T> consistentGet(List<MyReference<T>> references) { 
     final ArrayList<MyReference<T>> sortedReferences = Lists.newArrayList(references); 
     Collections.sort(sortedReferences); 
     for (val r : sortedReferences) r.lock(); 
     final List<T> result = Lists.newArrayListWithExpectedSize(sortedReferences.size()); 
     for (val r : references) result.add(r.value); 
     for (val r : sortedReferences) r.unlock(); 
     return result; 
    } 

    @Override 
    public int compareTo(MyReference<T> o) { 
     return id < o.id ? -1 : id > o.id ? 1 : 0; 
    } 

    private final static AtomicInteger counter = new AtomicInteger(); 

    private T value; 
    private final int id; 
} 
  • उपयोग AtomicReference के बजाय MyReference।
  • यह बहुत सारे ताले का उपयोग करता है, लेकिन उनमें से कोई भी वैश्विक नहीं है।
  • यह ताले को एक निश्चित क्रम में प्राप्त करता है, इसलिए यह डेडलॉक-मुक्त है।
  • यह लोम्बोक और अमरूद का उपयोग करके संकलित करता है (इसे बिना छद्म कोड के रूप में ले जाएं)।
+0

+1। लगभग मैं सुझाव देना चाहता था। हालांकि ओप को "इन संदर्भों में से सैकड़ों" की जरूरत है। शायद इन विभाजनों के साथ उन्हें विभाजन और सहयोगी ताले में समूहित करना बेहतर होगा, लगभग उसी तरह 'ConcurrentHashMap' कैसे काम करता है। यदि विभाजन की संख्या काफी बड़ी है, तो विवाद की संभावना कम होनी चाहिए। – axtavt

+0

मैं नहीं करता, क्योंकि ReentrantLock परी छोटी है क्योंकि इसमें खाली ऑब्जेक्ट का केवल एक संदर्भ है। इसलिए उनमें से एक मिलियन केवल 24 एमबी (प्रति संदर्भ 8 बी मानते हैं और प्रति ऑब्जेक्ट 16 बी) मानते हैं। – maaartinus

+0

@ मायार्टिनस, लोम्बोक का संदर्भ कहां है? – finnw

4

अपरिवर्तनीय वर्ग जोड़ी पकड़े है। वह आपका परमाणु है। जोड़ी की अदला-बदली परमाणु की जगह का मतलब है।

अपडेट: आपका प्रश्न बहुत स्पष्ट नहीं है। लेकिन सामान्य रूप से, एक समवर्ती प्रणाली के लिए एकाधिक चर शामिल होते हैं, एक

  1. सिस्टम स्थिति का एक स्नैपशॉट ले सकता है। एक बार लिया गया स्नैपशॉट नहीं बदलता है।
  2. परमाणु रूप से एक साथ कई चर बदलकर सिस्टम स्थिति अद्यतन करें। यह आवश्यक हो सकता है मेरी अद्यतन एक पिछले एक स्नैपशॉट (जो मेरी गणना के आधार पर किया गया था)

आप स्नैपशॉट में सीधे आपके सिस्टम मॉडल कर सकते हैं, अगर यह बहुत ज्यादा संसाधनों का उपभोग नहीं करता है के बीच कोई अन्य अद्यतन नहीं है।

+0

प्रश्न में पहला बुलेट बिंदु देखें। – finnw

+0

@finnw - इस उत्तर के साथ क्या गलत है? यह एक उचित (और बहुत कम जटिल) समाधान है। – jtahlborn

+0

मैं इस तथ्य का जिक्र कर रहा था कि एक ऑपरेशन के लिए 'आर 1' और' आर 2 'जोड़ा जा सकता है और' आर 1' और 'आर 3' को दूसरे के लिए जोड़ा जा सकता है। इस सिद्धांत में काम कर सकता था, लेकिन यह गतिशील रूप से समूह को पुनः के लिए संदर्भ के लिए एक रास्ता आवश्यकता होगी। – finnw