जावा थ्रेडलोकल वैरिएबल स्थिर क्यों होना चाहिए


101

मैं यहां थ्रेडलोक के लिए जावाडॉक पढ़ रहा था

https://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ThreadLocal.html

और यह कहता है कि "थ्रेडलोकल इंस्टेंस आमतौर पर निजी स्थिर क्षेत्र होते हैं, जो राज्य को एक धागे से जोड़ना चाहते हैं (जैसे, एक यूजर आईडी या ट्रांजेक्शन आईडी)।"

लेकिन मेरा सवाल यह है कि उन्होंने इसे स्थिर (आम तौर पर) बनाने के लिए क्यों चुना - यह चीजों को "प्रति थ्रेड" स्थिति के लिए थोड़ा भ्रमित करता है लेकिन क्षेत्र स्थिर हैं?

जवाबों:


131

क्योंकि यदि यह एक उदाहरण स्तर क्षेत्र था, तो यह वास्तव में "प्रति थ्रेड - प्रति उदाहरण" होगा, न कि केवल "प्रति थ्रेड"। यह आमतौर पर वह शब्दार्थ नहीं है जिसकी आपको तलाश है।

आमतौर पर यह कुछ ऐसी वस्तुओं को धारण करता है, जो किसी उपयोगकर्ता वार्तालाप, वेब रिक्वेस्ट इत्यादि के लिए स्कैन की जाती हैं, आप उन्हें कक्षा के उदाहरण से उप-स्कोप नहीं करना चाहते हैं।
एक वेब अनुरोध => एक दृढ़ता सत्र।
नहीं एक वेब अनुरोध => प्रति वस्तु एक हठ सत्र।


2
मुझे यह स्पष्टीकरण पसंद है क्योंकि यह दिखाता है कि
थ्रेडलोक का

4
प्रति-धागा-प्रति-इंस्टेंस एक उपयोगी शब्दार्थ हो सकता है, लेकिन उस पैटर्न के लिए अधिकांश उपयोग में कई ऑब्जेक्ट शामिल होंगे जो कि ThreadLocalहैश-सेट के संदर्भ को रखने के लिए बेहतर होगा कि ऑब्जेक्ट्स को प्रति-थ्रेड उदाहरणों में मैप करता है।
सुपरकाट

@ दत्तक इसका मतलब है कि गैर-स्थैतिक के प्रत्येक उदाहरण ThreadLocalका स्वयं का थ्रेड-स्थानीय डेटा होगा, भले ही वे ThreadLocalउदाहरण उसी थ्रेड में मौजूद हों। यह करना गलत नहीं है - मुझे लगता है कि यह सिर्फ दो का सबसे कम से कम लोकप्रिय पैटर्न हो सकता है
geg

17

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


12

यह होना जरूरी नहीं है। महत्वपूर्ण बात यह है कि यह एक सिंगलटन होना चाहिए।


3

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


1

एक थ्रेडलोक के लिए प्रति थ्रेड प्रति थ्रेड के लिए उपयोग है यदि आप चाहते हैं कि किसी ऑब्जेक्ट के सभी तरीकों में दृश्यमान हो और उसके पास पहुंच को सुरक्षित किए बिना थ्रेड सुरक्षित है जैसे कि आप एक साधारण फ़ील्ड के लिए ऐसा करेंगे।


1

इस का संदर्भ लें , इससे बेहतर समझ मिलती है।

संक्षेप में, ThreadLocalवस्तु की-वैल्यू मैप की तरह काम करती है। जब धागा आह्वानThreadLocal get/set विधि होती है, तो यह मैप की कुंजी में थ्रेड ऑब्जेक्ट को पुनः प्राप्त / संग्रहीत करेगा, और मैप के मूल्य में मूल्य। इसीलिए विभिन्न थ्रेड्स में मूल्य की अलग-अलग कॉपी होती है (जो आप स्थानीय रूप से स्टोर करना चाहते हैं), क्योंकि यह अलग-अलग मैप की प्रविष्टि में रहता है।

इसलिए आपको सभी मूल्यों को रखने के लिए केवल एक मानचित्र की आवश्यकता है। हालांकि आवश्यक नहीं है, आपके पास प्रत्येक थ्रेड ऑब्जेक्ट को रखने के लिए आपके पास कई नक्शे (स्थिर घोषित किए बिना) हो सकते हैं, जो कि, यह पूरी तरह से बेमानी है, यही कारण है कि स्थिर चर पसंद किया जाता है।


-1

static final ThreadLocal चर धागे सुरक्षित हैं।

staticकेवल संबंधित थ्रेड के लिए कई वर्गों में थ्रेडलोकल वैरिएबल उपलब्ध कराता है। यह कई वर्गों में संबंधित थ्रेड लोकल वैरिएबल का एक प्रकार का ग्लोबल वैरिएबल डिमार्केशन है।

हम निम्नलिखित कोड नमूने के साथ इस थ्रेड सुरक्षा की जांच कर सकते हैं।

  • CurrentUser - थ्रेडलोक में वर्तमान यूजर आईडी को स्टोर करता है
  • TestService- विधि के साथ सरल सेवा - getUser()करेंटयूसर से वर्तमान उपयोगकर्ता को लाने के लिए।
  • TestThread - यह क्लास कई थ्रेड बनाने के लिए उपयोग की जाती है और उपयोगकर्ता समवर्ती सेट करती है

public class CurrentUser

public class CurrentUser {
private static final ThreadLocal<String> CURRENT = new ThreadLocal<String>();

public static ThreadLocal<String> getCurrent() {
    return CURRENT;
}

public static void setCurrent(String user) {
    CURRENT.set(user);
}

}

public class TestService {

public String getUser() {
    return CurrentUser.getCurrent().get();
}

}

import java.util.ArrayList;
import java.util.List;

public class TestThread {

public static void main(String[] args) {

  List<Integer> integerList = new ArrayList<>();

  //creates a List of 100 integers
  for (int i = 0; i < 100; i++) {

    integerList.add(i);
  }

  //parallel stream to test concurrent thread execution
  integerList.parallelStream().forEach(intValue -> {

    //All concurrent thread will set the user as "intValue"
    CurrentUser.setCurrent("" + intValue);
    //Thread creates a sample instance for TestService class
    TestService testService = new TestService();
    //Print the respective thread name along with "intValue" value and current user. 
    System.out.println("Start-"+Thread.currentThread().getName()+"->"+intValue + "->" + testService.getUser());

    try {
      //all concurrent thread will wait for 3 seconds
      Thread.sleep(3000l);
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

    //Print the respective thread name along with "intValue" value and current user.
    System.out.println("End-"+Thread.currentThread().getName()+"->"+intValue + "->" + testService.getUser());
  });

}

}

TestThread मुख्य वर्ग चलाएं। आउटपुट -

Start-main->62->62
Start-ForkJoinPool.commonPool-worker-2->31->31
Start-ForkJoinPool.commonPool-worker-3->81->81
Start-ForkJoinPool.commonPool-worker-1->87->87
End-main->62->62
End-ForkJoinPool.commonPool-worker-1->87->87
End-ForkJoinPool.commonPool-worker-2->31->31
End-ForkJoinPool.commonPool-worker-3->81->81
Start-ForkJoinPool.commonPool-worker-2->32->32
Start-ForkJoinPool.commonPool-worker-3->82->82
Start-ForkJoinPool.commonPool-worker-1->88->88
Start-main->63->63
End-ForkJoinPool.commonPool-worker-1->88->88
End-main->63->63
...

विश्लेषण सारांश

  1. "मुख्य" धागा "62" के रूप में वर्तमान उपयोगकर्ता को शुरू और सेट करता है, समानांतर रूप से "ForkJoinPool.commonPool-कार्यकर्ता -2" धागा शुरू होता है और वर्तमान उपयोगकर्ता को "31" के रूप में सेट करता है, समान रूप से "ForkJoinPool.commonPool-कार्यकर्ता-3" धागा शुरू होता है और वर्तमान सेट करता है उपयोगकर्ता "81" के रूप में, समान रूप से "ForkJoinPool.commonPool-worker-1" थ्रेड शुरू होता है और वर्तमान उपयोगकर्ता को "87" स्टार्ट-मेन-> 62-> 62 स्टार्ट-फॉर जॉइंटपूल.कॉमmonPool-कार्यकर्ता-2-> 31-> 31 के रूप में सेट करता है Start-ForkJoinPool.commonPool-worker-3-> 81-> 81 Start-ForkJoinPool.commonPool-कार्यकर्ता-1-> 87-> 87
  2. उपरोक्त सभी धागे 3 सेकंड तक सोएंगे
  3. mainनिष्पादन समाप्त होता है और वर्तमान उपयोगकर्ता को "62" के रूप में प्रिंट करता है, समानांतर ForkJoinPool.commonPool-worker-1निष्पादन समाप्त होता है और वर्तमान उपयोगकर्ता को "87" के रूप में प्रिंट करता है, समानांतर ForkJoinPool.commonPool-worker-2निष्पादन समाप्त होता है और वर्तमान उपयोगकर्ता को "31" के रूप में प्रिंट करता है, समानांतर ForkJoinPool.commonPool-worker-3निष्पादन समाप्त होता है और वर्तमान उपयोगकर्ता को "81" के रूप में प्रिंट करता है।

अनुमान

समवर्ती थ्रेड्स सही उपयोगकर्ता प्राप्त करने में सक्षम हैं, भले ही इसे "स्थिर अंतिम थ्रेडलोकल" घोषित किया गया हो

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.