Java Academy · पाठ

थ्रेड सुरक्षा और साइड इफ़ेक्ट

साझी परिवर्तनीय स्थिति से बचें

पाठ 3, कुल 4 में से13 चरण

थ्रेड सुरक्षा और साइड इफ़ेक्ट, CoddyKit पर Java Academy का एक निःशुल्क पाठ है। यह 4 में से 3वाँ पाठ है। आप नीचे पूरा पाठ निःशुल्क पढ़ सकते हैं—फिर अंतर्निहित कोड संपादक और 24/7 एआई ट्यूटर के साथ ब्राउज़र में इसका व्यावहारिक अभ्यास कर सकते हैं। यह Java Academy सीखने के मार्ग का हिस्सा है और आपकी प्रगति वेब तथा CoddyKit ऐप पर सिंक होती रहती है। Java Academy पाठ्यक्रम में कुल 4 पाठ शामिल हैं।

समानांतरता का अर्थ समवर्ती पहुँच है

समानांतर stream में कई थ्रेड आपके लैम्ब्डा को एक ही समय पर चलाते हैं। उनके द्वारा छुई गई कोई भी साझा परिवर्तनीय स्थिति दौड़ की स्थिति बन जाती है।

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        int safe = IntStream.rangeClosed(1, 1000).parallel().sum();
        System.out.println(safe);
    }
}

खतरा: साझा चर को बदलना

कई थ्रेड द्वारा उपयोग किया गया साधारण int गणक कुछ अद्यतन खो देता है। forEach के भीतर साझा परिवर्तनीय स्थिति में कभी भी संचय न करें।

import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        AtomicInteger counter = new AtomicInteger();
        IntStream.rangeClosed(1, 1000).parallel()
            .forEach(n -> counter.incrementAndGet());
        System.out.println(counter.get());
    }
}

साधारण संग्रह क्यों विफल होते हैं

समानांतर forEach से थ्रेड-सुरक्षित न होने वाले ArrayList में जोड़ने पर वह दूषित हो सकता है या उसमें से तत्व गायब हो सकते हैं। समाधान यह है कि साझा करके बदलने से पूरी तरह बचें।

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        List<Integer> result = IntStream.rangeClosed(1, 10).parallel()
            .boxed()
            .collect(Collectors.toList());
        System.out.println(result.size());
    }
}

सही उपकरण: collect

पार्श्व-प्रभाव वाले forEach के बजाय collect का उपयोग करें। संग्रहक ढाँचा हर थ्रेड के लिए आंशिक कंटेनरों में सुरक्षित रूप से संचय करता है और उन्हें मिला देता है।

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        List<Integer> squares = IntStream.rangeClosed(1, 6).parallel()
            .map(n -> n * n)
            .boxed()
            .collect(Collectors.toList());
        System.out.println(squares);
    }
}

सही उपकरण: reduce

जब क्रिया साहचर्यात्मक और स्थिति-रहित हो, तो reduce स्वभावतः थ्रेड-सुरक्षित होता है, क्योंकि यह साझा परिवर्तन के बिना आंशिक परिणामों को मिलाता है।

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        int sum = IntStream.rangeClosed(1, 1000).parallel()
            .reduce(0, Integer::sum);
        System.out.println(sum);
    }
}

स्थिति-रहित लैम्ब्डा

stream में लैम्ब्डा स्थिति-रहित होने चाहिए: उनका परिणाम केवल प्रवेश मान पर निर्भर हो, बाहरी परिवर्तनीय चरों या पहले के तत्वों पर नहीं।

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        long count = IntStream.rangeClosed(1, 1000).parallel()
            .filter(n -> n % 2 == 0)
            .count();
        System.out.println(count);
    }
}

परमाण्विक प्रकारों का विकल्प

यदि आपको सचमुच कोई गणक साझा करना ही पड़े, तो AtomicLong जैसे परमाण्विक वर्गों का उपयोग करें। वे अद्यतनों को सही ढंग से क्रमबद्ध करते हैं, हालांकि इससे प्रतिस्पर्धा बढ़ती है।

import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        AtomicLong sum = new AtomicLong();
        IntStream.rangeClosed(1, 1000).parallel()
            .forEach(sum::addAndGet);
        System.out.println(sum.get());
    }
}

समवर्ती संग्रह

जब आपको थ्रेड के बीच साझा मानचित्र चाहिए, तो ConcurrentHashMap सुरक्षित है। फिर भी, जहाँ संभव हो, Collectors.groupingByConcurrent को प्राथमिकता दें।

import java.util.Map;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<String> words = List.of("a", "bb", "cc", "ddd");
        Map<Integer, List<String>> byLen = words.parallelStream()
            .collect(Collectors.groupingByConcurrent(String::length));
        System.out.println(byLen);
    }
}

क्रम-निर्भर तर्क से बचें

समानांतर लैम्ब्डा के भीतर प्राप्ति क्रम पर निर्भर न रहें। क्रमिक प्रसंस्करण मानने वाली क्रियाएँ parallel में गलत परिणाम देती हैं।

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        int sum = IntStream.rangeClosed(1, 100).parallel()
            .map(n -> n * 2)
            .sum();
        System.out.println(sum);
    }
}

शुद्ध फ़ंक्शन सुरक्षित रूप से parallel होते हैं

स्वर्णिम नियम है: शुद्ध, स्थिति-रहित और अहस्तक्षेपी क्रियाएँ लिखें। तब stream क्रमिक हो या parallel, परिणाम समान और सही रहेंगे।

import java.util.List;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<String> in = List.of("red", "green", "blue");
        String out = in.parallelStream()
            .map(String::toUpperCase)
            .sorted()
            .collect(Collectors.joining(","));
        System.out.println(out);
    }
}

अहस्तक्षेप

जब stream किसी संग्रह पर चल रहा हो, तब स्रोत संग्रह को न बदलें। इससे ConcurrentModificationException या अपरिभाषित व्यवहार हो सकता है, चाहे निष्पादन sequential हो या parallel।

import java.util.List;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<Integer> src = List.of(1, 2, 3, 4);
        List<Integer> doubled = src.parallelStream()
            .map(n -> n * 2)
            .collect(Collectors.toList());
        System.out.println(doubled);
    }
}

त्वरित जाँच

समानांतर stream से परिणामों का संचय करने का अनुशंसित तरीका क्या है?

पुनरावलोकन

आपने समानांतर stream को सही बनाए रखा:

  • समानांतर लैम्ब्डा में साझा परिवर्तनीय स्थिति दौड़ की स्थितियाँ पैदा करती है।
  • पार्श्व-प्रभाव वाले forEach के बजाय collect और reduce को प्राथमिकता दें।
  • लैम्ब्डा को स्थिति-रहित, शुद्ध और अहस्तक्षेपी रखें।
  • यदि साझा करना आवश्यक हो, तो परमाण्विक या समवर्ती संग्रहों का उपयोग करें, लेकिन यह अंतिम उपाय होना चाहिए।
शुरुआत निःशुल्क

एआई शिक्षक के साथ Java सीखें — निःशुल्क

अपने ब्राउज़र में वास्तविक कोड लिखें और चलाएँ, चौबीसों घंटे एआई शिक्षक से तुरंत सहायता पाएँ, और वेब या ऐप पर वहीं से शुरू करें जहाँ आपने छोड़ा था।

पाठ्यक्रम
104
पाठ
374

अक्सर पूछे जाने वाले प्रश्न

क्या “थ्रेड सुरक्षा और साइड इफ़ेक्ट” पाठ निःशुल्क है?

हाँ—“थ्रेड सुरक्षा और साइड इफ़ेक्ट” का पूरा पाठ यहाँ वेब पर निःशुल्क पढ़ा जा सकता है। इंटरैक्टिव अभ्यास (अंतर्निहित कोड संपादक और 24/7 एआई ट्यूटर) करने और Java Academy पाठ्यक्रम का बाकी हिस्सा अनलॉक करने के लिए CoddyKit PRO लें। Java Academy पाठ्यक्रम में कुल 4 पाठ शामिल हैं।

“थ्रेड सुरक्षा और साइड इफ़ेक्ट” में मैं क्या सीखूँगा?

साझी परिवर्तनीय स्थिति से बचें आप ब्राउज़र में सीधे चलाए जाने वाले व्यावहारिक कोड के साथ Java Academy का अभ्यास करते हैं, और पाठ पूरा करते समय 24/7 एआई ट्यूटर आपके प्रश्नों के उत्तर देता है।

क्या Java Academy शुरू करने के लिए मुझे किसी अनुभव की आवश्यकता है?

पहले के अनुभव की आवश्यकता नहीं है। CoddyKit पर Java Academy शुरुआती से लेकर उन्नत शिक्षार्थियों तक सभी के लिए व्यवस्थित किया गया है, इसलिए आप यहीं से या शुरुआत से सीखना शुरू कर सकते हैं और अपनी गति से आगे बढ़ सकते हैं। यह 4 में से 3वाँ पाठ है।

“थ्रेड सुरक्षा और साइड इफ़ेक्ट” पाठ पूरा करने में कितना समय लगता है?

CoddyKit का अधिकांश पाठ लगभग 5–10 मिनट में पूरा हो जाता है। हर पाठ छोटा और संवादात्मक है, इसलिए आप लगातार प्रगति करते हैं और वेब या ऐप पर वहीं से सीखना जारी रख सकते हैं जहाँ आपने छोड़ा था।

क्या मैं इस Java Academy पाठ में कोड लिख और चला सकता हूँ?

हाँ। हर Java Academy पाठ में एक अंतर्निर्मित कोड संपादक शामिल है, जिससे आप सीधे अपने ब्राउज़र में वास्तविक कोड लिख और चला सकते हैं और तुरंत एआई प्रतिक्रिया पा सकते हैं—स्थानीय सेटअप की आवश्यकता नहीं है।

इस पाठ्यक्रम के सभी पाठ

  1. पैरेलल स्ट्रीम बनाना
  2. पैरेललिज़्म कब उपयोगी है
  3. थ्रेड सुरक्षा और साइड इफ़ेक्ट
  4. सामान्य समस्याएँ
← Java Academy पर वापस जाएँ