আমার কখন এবং কীভাবে একটি থ্রেডলোকাল ভেরিয়েবল ব্যবহার করা উচিত?


874

আমার কখন ThreadLocalপরিবর্তনশীল ব্যবহার করা উচিত ?

এটি কীভাবে ব্যবহৃত হয়?


11
আপনি যদি থ্রেডলোকাল ব্যবহার করছেন তবে এর উপর কখনই একটি মোড়ক লিখবেন না !!! প্রতিটি বিকাশকারী যারা ভেরিয়েবলটি ব্যবহার করতে চান তাদের অবশ্যই এটি 'থ্রেডলোকাল' জেনে থাকতে হবে
কোনও বাগ

2
@ নোটব্যাগ আপনি যদি স্পষ্ট হন তবে আপনি আপনার ভেরিয়েবলটির নাম রাখতে পারেন যাতে আপনি থ্রেডলোকাল মানটি ব্যবহার করছেন, যেমন RequestUtils.getCurrentRequestThreadLocal()। এটি যদিও খুব মার্জিত তা না বলা, তবে এটি থ্রেডলোকাল নিজেই বেশিরভাগ ক্ষেত্রে খুব মার্জিত নয় এই সত্যটি থেকে উদ্ভূত হয়।
ঘূর্ণি

@Sasha ThreadLocal দোকান সঞ্চালনের ট্রেস ব্যবহার করা যাবে
গৌরব

উত্তর:


863

একটি সম্ভাব্য (এবং সাধারণ) ব্যবহার হ'ল যখন আপনার কাছে এমন কিছু বস্তু রয়েছে যা থ্রেড-নিরাপদ নয়, তবে আপনি সেই অবজেক্টে সিঙ্ক্রোনাইজ অ্যাক্সেস এড়াতে চান (আমি আপনাকে দেখছি, সিম্পলডেট ফরমেট )। পরিবর্তে, প্রতিটি থ্রেডকে বস্তুর নিজস্ব উদাহরণ দিন।

উদাহরণ স্বরূপ:

public class Foo
{
    // SimpleDateFormat is not thread-safe, so give one to each thread
    private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
        @Override
        protected SimpleDateFormat initialValue()
        {
            return new SimpleDateFormat("yyyyMMdd HHmm");
        }
    };

    public String formatIt(Date date)
    {
        return formatter.get().format(date);
    }
}

ডকুমেন্টেশন


160
সিঙ্ক্রোনাইজেশন বা থ্রেডলোকালের আরেকটি বিকল্প হ'ল ভেরিয়েবলটিকে স্থানীয় পরিবর্তনশীল করে তোলা। স্থানীয় যুদ্ধগুলি সর্বদা থ্রেড নিরাপদ থাকে। আমি ধরে নিয়েছি যে ডেটফর্ম্যাটগুলি স্থানীয়ভাবে তৈরি করা খারাপ অভ্যাস, কারণ সেগুলি তৈরি করা ব্যয়বহুল, তবে আমি এই বিষয়টিতে কখনও শক্ত মেট্রিক্স দেখিনি।
জুলিয়েন চস্তং 4:39

18
হ্যাকিংয়ের জন্য মূল্য দিতে এটি উচ্চ মূল্য SimpleDateFormatথ্রেড-নিরাপদ বিকল্প ব্যবহার করা আরও ভাল । যদি আপনি সম্মত হন যে সিলেটলেটগুলি খারাপ তবে ThreadLocalএটি আরও খারাপ।
আলেকজান্ডার রায়ঝভ

3
@ ওভারথিংক থ্রেডলোকাল স্থির এবং চূড়ান্ত ঘোষণার কোনও কারণ আছে, মানে পারফরম্যান্স বা কিছু?
শচীন গোরাদে 4'15

4
ThreadLocal.get () পদ্ধতিটি প্রতিটি থ্রেডের জন্য ThreadLocal.initialValue () (একবার) কল করবে, যার অর্থ প্রতিটি থ্রেডের জন্য একটি সরলডেটফর্ম্যাট অবজেক্ট তৈরি করা হয়েছে। কেবল স্থানীয় ভেরিয়েবল হিসাবে সিম্পলডেট ফরমেট রাখা ভাল না (যেহেতু আমাদের আবর্জনা সংগ্রহের সমস্যাগুলি মোকাবেলা করতে হবে না)?
sudeepdino008

3
আপনার সিম্পলডেট ফরমেটের জন্য ডাবল ব্রেস সূচনাটি ব্যবহার না করার জন্য কেবল সাবধান হন কারণ এটি একটি বেনাম শ্রেণি তৈরি করবে যাতে আপনার শ্রেণি লোডার আবর্জনা সংগ্রহ করা যায় না। মেমরি ফাঁস: নতুন সিম্পলডেটফরম্যাট () {{প্রয়োগপ্যাটরন ("yyyyMMdd HHmm") ফেরান}};
ব্যবহারকারী 1944408

426

যেহেতু একটি প্রদত্তের ThreadLocalমধ্যে থাকা ডেটাগুলির একটি রেফারেন্স Thread, তাই ThreadLocalথ্রেড পুল ব্যবহার করে অ্যাপ্লিকেশন সার্ভারে এস ব্যবহার করার সময় আপনি ক্লাসলোডিং লিক দিয়ে শেষ করতে পারেন । আপনার কোনও পরিষ্কার করার বিষয়ে বা এর পদ্ধতিটি ব্যবহার করে ThreadLocalআপনার খুব সতর্ক হওয়া দরকার ।get()set()ThreadLocalremove()

আপনার কাজ শেষ হয়ে গেলে আপনি যদি পরিষ্কার না করেন তবে এটি মোতায়েন করা ওয়েব অ্যাপের অংশ হিসাবে লোড হওয়া ক্লাসগুলিতে থাকা কোনও রেফারেন্স স্থায়ী স্তূপে থাকবে এবং কখনই আবর্জনা সংগ্রহ করা যাবে না। ওয়েব অ্যাপ্লিকেশনটিকে পুনরায় প্রচার / অপ্রকাশিত Threadকরা আপনার ওয়েবঅ্যাপের ক্লাসের প্রত্যেকের রেফারেন্স পরিষ্কার করবে না (কারণ) এটি Threadআপনার ওয়েবঅ্যাপের মালিকানাধীন কিছু নয়। প্রতিটি ক্রমাগত মোতায়েন ক্লাসের একটি নতুন উদাহরণ তৈরি করবে যা কখনই আবর্জনা সংগ্রহ করা হবে না।

আপনার কারণে স্মৃতি ব্যতিক্রমগুলি শেষ হয়ে যাবে java.lang.OutOfMemoryError: PermGen spaceএবং কিছু গুগলিং সম্ভবত -XX:MaxPermSizeবাগ ঠিক করার পরিবর্তে বাড়বে ।

যদি আপনি এই সমস্যাগুলির মুখোমুখি না হয়ে থাকেন তবে আপনি নির্ধারণ করতে পারবেন কোন থ্রেড এবং শ্রেণি একটিগ্রহের স্মৃতি বিশ্লেষক এবং / অথবা ফ্রাঙ্ক কিয়েটের গাইড এবং ফলোআপ অনুসরণ করে এই রেফারেন্সগুলি ধরে রেখেছে ।

আপডেট: অ্যালেক্স ভাসিউরের ব্লগ এন্ট্রি পুনরায় আবিষ্কার করে যা আমাকে যা কিছু ThreadLocalসমস্যা ছিল তা সন্ধান করতে সহায়তা করে।


11
অ্যালেক্স ভাসিউর তার ব্লগ সরিয়ে নিয়েছেন। এখানে মেমরি ফাঁস নিবন্ধের একটি বর্তমান লিঙ্ক।
কেনস্টার

12
জুলিয়েন যে সুতোর সাথে লিঙ্ক করেছেন তা এখানে এসে গেছে বলে মনে হয়, এবং এটি পড়ার
ডোনাল ফেলো

28
এটি একটি উত্তরের জন্য অত্যন্ত উদ্দীপনা যা তথ্যবহুল হলেও কোনওভাবেই প্রশ্নের উত্তর দেয় না।
রবিন

7
এখন যেহেতু PermGen জাভা 8 দ্বারা নিহত হয়েছে, এই উত্তরটি কোনও উপায়ে পরিবর্তন করে?
এভিল ওয়াশিং মেশিন

12
@ রবিন: আমি একমত নই থ্রেডলোকালকে সঠিকভাবে কীভাবে ব্যবহার করা যায়, কোনও ধারণার (থ্রেডলোকাল) এখানে সম্পূর্ণ কীভাবে ব্যবহার করা যায় না এবং এটি কীভাবে অযত্নে ব্যবহার করার ঝুঁকি রয়েছে তাও বোঝা গুরুত্বপূর্ণ এবং ফিলের উত্তর কী তা সম্পর্কে। আমি আনন্দিত যে তিনি সেই বিষয়টিকে coveredেকে রেখেছিলেন যা অন্য কোনও উত্তরে coveredাকা নেই। এই সমস্ত ভোট ভাল প্রাপ্য। আমি বিশ্বাস করি যে এসও'র কেবল একটি QA সাইট না হয়ে ধারণাগুলি বোঝা উচিত।
সৌরভ পাতিল

166

অনেকগুলি ফ্রেমওয়ার্ক বর্তমান থ্রেড সম্পর্কিত কিছু প্রসঙ্গ বজায় রাখতে থ্রেডলোকাল ব্যবহার করে als উদাহরণস্বরূপ, যখন বর্তমান লেনদেনটি থ্রেডলোকল এ সঞ্চিত থাকে, আপনাকে স্ট্যাকের নিচে কারও কাছে অ্যাক্সেসের প্রয়োজন হলে প্রতিটি পদ্ধতি কলের মাধ্যমে প্যারামিটার হিসাবে পাস করার দরকার নেই। ওয়েব অ্যাপ্লিকেশনগুলি বর্তমান অনুরোধ এবং সেশন সম্পর্কে তথ্য একটি থ্রেডলোকলে সংরক্ষণ করতে পারে যাতে অ্যাপ্লিকেশনটিতে তাদের সহজেই অ্যাক্সেস থাকে। ইনজেকশনের জন্য কাস্টম স্কোপগুলি প্রয়োগ করার সময় গুইসের সাহায্যে আপনি থ্রেডলোকালস ব্যবহার করতে পারেন (গুইসের ডিফল্ট সার্ভলেট স্কোপগুলি সম্ভবত সেগুলি ব্যবহার করে)।

থ্রেডলোকালগুলি এক ধরণের গ্লোবাল ভেরিয়েবল (যদিও কিছুটা কম খারাপ কারণ সেগুলি একটি থ্রেডের মধ্যে সীমাবদ্ধ) তবে অযাচিত পার্শ্ব প্রতিক্রিয়া এবং মেমরি ফাঁস এড়াতে তাদের ব্যবহার করার সময় আপনার সতর্কতা অবলম্বন করা উচিত। আপনার এপিআইগুলি ডিজাইন করুন যাতে থ্রেডলোকাল মানগুলি যখন আর প্রয়োজন হয় না তখন সর্বদা স্বয়ংক্রিয়ভাবে সাফ হয়ে যায় এবং এপিআই-র ভুল ব্যবহার সম্ভব হবে না (উদাহরণস্বরূপ এর মতো )। থ্রেডলোকালস কোড ক্লিনার তৈরি করতে ব্যবহার করা যেতে পারে এবং কিছু বিরল ক্ষেত্রে এগুলি কিছু কাজ করার একমাত্র উপায় (আমার বর্তমান প্রকল্পে এরকম দুটি ক্ষেত্রে ছিল; সেগুলি এখানে "স্ট্যাটিক ফিল্ডস এবং গ্লোবাল ভেরিয়েবলস" এর অধীনে নথিভুক্ত করা হয়েছে )।


4
ঠিক এভাবেই এক্সপোজো ফ্রেমওয়ার্ক (www.expojo.com) অ্যানোটেশন এবং ইনজেকশনের ওভারহেডের প্রয়োজন ছাড়াই ওআরএম সেশন / পার্সিস্ট্যান্স ম্যানেজারে অ্যাক্সেসের অনুমতি দেয়। এটি 'অবজেক্ট ইনজেকশন' এর পরিবর্তে 'থ্রেড ইনজেকশন' এর মতো। এটি প্রয়োজনীয়তার (এবং ওভারহেড) ছাড়াই নির্ভরশীলতার অ্যাক্সেস সরবরাহ করে যা তাদের প্রতিটি বস্তুতে এম্বেড করে those ক্লাসিক ডিআই (উদাহরণস্বরূপ, স্প্রিং ইত্যাদি) এর পরিবর্তে থ্রেড ইনজেকশন ব্যবহার করার সময় আপনি কীভাবে 'হালকা ওজন' ডিআই ফ্রেমওয়ার্ক তৈরি করতে পারেন তা আশ্চর্যজনক
ভোকসম্যান

27
এই প্রয়োজনীয় উত্তরটি খুঁজে পেতে আমাকে কেন এতক্ষণ নীচে নামতে হয়েছিল !?
জেরেমি স্টেইন

1
@ এসকো, আপনার প্রকল্পে আপনার হ্যাশকোড এবং সমতুল্যে থ্রেডলোকালের ব্যবহার বিনা বাঁধা। একটি হ্যাশকোড / ইক্যুয়াল ফাংশন যখনই প্রয়োজন হয় তখন একটি রেফারেন্স তৈরি বা পাস করা আরও ভাল পদ্ধতির। এইভাবে, আপনি সম্পূর্ণভাবে থ্রেডলোকাল হ্যাকের জন্য প্রয়োজনীয়তা এড়াতে পারবেন।
পেসারিয়ার

1
@JeremyStein, সবচেয়ে ভালো উত্তর দিকে রয়েছে stackoverflow.com/a/817911/632951 এবং stackoverflow.com/a/17398338/632951 এবং stackoverflow.com/a/818364/632951
Pacerier

1
এটি টিএল ব্যবহারের সেরা ব্যাখ্যা is
ডেক্সটার

51

জাভাতে, যদি আপনার কাছে কোনও থ্যাটাম থাকে যা প্রতি-থ্রেডে পরিবর্তিত হতে পারে তবে আপনার পছন্দগুলি সেই ডাটামকে প্রয়োজনীয় প্রতিটি পদ্ধতিতে (বা প্রয়োজন হতে পারে) এর কাছাকাছি পৌঁছে দেওয়া বা ডাটামকে থ্রেডের সাথে যুক্ত করতে হবে। আপনার সমস্ত পদ্ধতি যদি ইতিমধ্যে একটি সাধারণ "প্রসঙ্গ" ভেরিয়েবলের চারপাশে পাস করার প্রয়োজন হয় তবে সর্বত্র সর্বত্র ডেটাম পাস করা কার্যকর হবে।

যদি এটি না হয়, আপনি অতিরিক্ত প্যারামিটার দিয়ে আপনার পদ্ধতি স্বাক্ষরগুলি বিশৃঙ্খলা করতে না চাইতে পারেন। একটি থ্রেডবিহীন বিশ্বে আপনি বৈশ্বিক ভেরিয়েবলের জাভা সমতুল্য সমস্যাটি সমাধান করতে পারেন। একটি থ্রেড শব্দের সাথে, বিশ্বব্যাপী ভেরিয়েবলের সমতুল্য হ'ল থ্রেড-লোকাল ভেরিয়েবল।


13
সুতরাং গ্লোবালগুলি এড়াতে আপনার যেমন থ্রেড স্থানীয়দের এড়ানো উচিত। আমি সম্ভবত মেনে নিতে পারি না যে চারপাশের মানগুলি পাস করার পরিবর্তে গ্লোবাল (থ্রেড লোকাল) তৈরি করা ঠিক আছে, লোকেরা পছন্দ করে না কারণ এটি প্রায়শই আর্কিটেকচার সমস্যাগুলি প্রকাশ করে যা তারা ঠিক করতে চান না।
জুয়ান মেন্ডেস

10
সম্ভবত ... এটি কার্যকর হতে পারে, যদিও আপনার যদি একটি বিশাল, বিদ্যমান কোডবেস থাকে যেখানে আপনাকে একটি নতুন ডেটুম যোগ করতে হবে যা সর্বত্রই পাস করতে হবে , যেমন একটি সেশন প্রসঙ্গ, ডিবি লেনদেন, লগ-ইন করা ব্যবহারকারী ইত্যাদি ।
কর্নেল ম্যাসন

5
ডেটা পরিবর্তে ড্যাটুম ব্যবহারের জন্য কুডোস।
গভীর

23

অনুশীলনে জাভা কনকুরেন্সি বইয়ের খুব ভাল উদাহরণ রয়েছে । যেখানে লেখক ( জোশুয়া ব্লচ ) ব্যাখ্যা করেছেন যে কীভাবে থ্রেড কারাবাস থ্রেড সুরক্ষা এবং থ্রেডলোকাল অর্জনের অন্যতম সহজ উপায় is বজায় রাখার আরও আনুষ্ঠানিক উপায়। শেষ পর্যন্ত তিনি আরও ব্যাখ্যা করেছেন যে কীভাবে লোকেরা এটির বৈশ্বিক চলক হিসাবে এটি ব্যবহার করতে পারে abuse

আমি উল্লিখিত বই থেকে পাঠ্যটি অনুলিপি করেছি তবে কোড 3.10 অনুপস্থিত কারণ থ্রেডলোকালটি কোথায় ব্যবহার করা উচিত তা বোঝা খুব বেশি গুরুত্বপূর্ণ নয়।

থ্রেড-লোকাল ভেরিয়েবলগুলি প্রায়শই পরিবর্তিত সিঙ্গললেট বা গ্লোবাল ভেরিয়েবলের উপর ভিত্তি করে ডিজাইনে ভাগ করা রোধ করতে ব্যবহৃত হয়। উদাহরণস্বরূপ, একক থ্রেডযুক্ত অ্যাপ্লিকেশনটি কোনও গ্লোবাল ডাটাবেস সংযোগ বজায় রাখতে পারে যা প্রতিটি পদ্ধতিতে সংযোগটি পাস না করে এড়াতে প্রারম্ভকালে শুরু করা হয়। যেহেতু জেডিবিসি সংযোগগুলি থ্রেড-নিরাপদ নাও হতে পারে, অতিরিক্ত সমন্বয় ছাড়াই বিশ্বব্যাপী সংযোগ ব্যবহার করে এমন একাধিক সংযুক্ত অ্যাপ্লিকেশন থ্রেড-নিরাপদ নয়। জেডিবিসি সংযোগ সঞ্চয় করার জন্য একটি থ্রেডলোকাল ব্যবহার করে, যেমন 3.10 তালিকাতে সংযোগহোল্ডার হিসাবে, প্রতিটি থ্রেডের নিজস্ব সংযোগ থাকবে।

থ্রেডলোকাল অ্যাপ্লিকেশন ফ্রেমওয়ার্ক কার্যকর করতে ব্যাপকভাবে ব্যবহৃত হয়। উদাহরণস্বরূপ, জে 2 ই ই ধারকগুলি একটি ইজেবি কলটির সময়কালের জন্য একটি এক্সিকিউটিভ থ্রেডের সাথে লেনদেনের প্রসঙ্গে যুক্ত করে। এটি লেনদেনের প্রসঙ্গটি ধরে রেখে একটি স্ট্যাটিক থ্রেড-লোকাল ব্যবহার করে সহজেই প্রয়োগ করা হয়: যখন ফ্রেমওয়ার্ক কোডটিতে বর্তমানে কোন লেনদেন চলছে তা নির্ধারণ করা দরকার, এটি এই থ্রেডলোকাল থেকে লেনদেনের প্রসঙ্গটি এনেছে। এটি সুবিধাজনক যে এটি প্রতিটি পদ্ধতির মধ্যে কার্যকরকরণ প্রসঙ্গে তথ্য প্রেরণের প্রয়োজনীয়তা হ্রাস করে তবে ফ্রেমওয়ার্কে এই প্রক্রিয়াটি ব্যবহার করে এমন কোনও কোড যুক্ত করে।

থ্রেডলোকালকে গ্লোবাল ভেরিয়েবলগুলি ব্যবহারের লাইসেন্স হিসাবে বা "লুকানো" পদ্ধতির যুক্তি তৈরির মাধ্যম হিসাবে ব্যবহার করে তার থ্রেড বন্দি সম্পত্তি হিসাবে ব্যবহার করা সহজ। গ্লোবাল ভেরিয়েবলের মতো, থ্রেড-লোকাল ভেরিয়েবলগুলি পুনরায় ব্যবহারযোগ্যতা থেকে বিরত করতে পারে এবং ক্লাসগুলির মধ্যে লুকানো কাপলিংগুলি প্রবর্তন করতে পারে এবং তাই যত্ন সহ ব্যবহার করা উচিত।


18

মূলত, আপনি একটি প্রয়োজন যখন পরিবর্তনশীল এর মান বর্তমান থ্রেড উপর নির্ভর করে এবং এটি সুবিধাজনক আপনি অন্য কোন উপায়ে থ্রেড মান সংযুক্ত করতে জন্য নয় (উদাহরণস্বরূপ, থ্রেড subclassing)।

একটি সাধারণ কেস যেখানে অন্য কিছু কাঠামো থ্রেড তৈরি করেছে যা আপনার কোডটি চালু রয়েছে, যেমন একটি সার্লেট পাত্রে, অথবা যেখানে থ্রেডলোকালটি ব্যবহার করা আরও বেশি অর্থবোধ করে কারণ আপনার ভেরিয়েবলটি "তার যৌক্তিক স্থানে" (পরিবর্তকের পরিবর্তে) একটি থ্রেড সাবক্লাস থেকে বা অন্য কোনও হ্যাশ মানচিত্রে ঝুলানো)।

আমার ওয়েবসাইটে আমার থ্রেডলোকাল কখন ব্যবহার করতে হবে সে সম্পর্কে আরও কিছু আলোচনা এবং উদাহরণ রয়েছে যা আগ্রহীও হতে পারে।

কিছু লোক থ্রডলোকালকে নির্দিষ্ট থ্রিজি সংযুক্ত অ্যালগরিদমগুলিতে প্রতিটি থ্রেডের সাথে একটি "থ্রেড আইডি" সংযুক্ত করার উপায় হিসাবে সমর্থন করে যেখানে আপনার থ্রেড নম্বর প্রয়োজন (উদাহরণস্বরূপ হার্লিহী এবং শভিট)। এই ক্ষেত্রে, আপনি সত্যিই একটি সুবিধা পাচ্ছেন তা পরীক্ষা করে দেখুন!


থ্রেডলোকালকে এক্সিকিউশন ট্রেস সংরক্ষণ করতে ব্যবহার করা যেতে পারে
গৌরব

13
  1. জাভাতে থ্রেডলোকালটি জেডিকে ১.২ এ প্রবর্তিত হয়েছিল তবে থ্রেডলোকাল ভেরিয়েবলের ধরণের সুরক্ষা প্রবর্তনের জন্য পরে জেডিকে ২.৩ এ জেনারাইড করা হয়েছিল।

  2. থ্রেডলোকাল থ্রেড স্কোপের সাথে যুক্ত হতে পারে, থ্রেড দ্বারা সম্পাদিত সমস্ত কোডের থ্রেডলোকাল ভেরিয়েবলের অ্যাক্সেস রয়েছে তবে দুটি থ্রেড একে অপরকে থ্রেডলোকাল ভেরিয়েবল দেখতে পাবে না।

  3. প্রতিটি থ্রেডে থ্রেডলোকাল ভেরিয়েবলের একচেটিয়া অনুলিপি থাকে যা থ্রেড শেষ হয়ে গেলে বা মারা যায়, সাধারণত বা কোনও ব্যতিক্রমের কারণে, থ্রেডলোকাল ভেরিয়েবলের কোনও অন্য লাইভ উল্লেখ নেই।

  4. জাভাতে থ্রেডলোকাল ভেরিয়েবলগুলি সাধারণত ক্লাসে ব্যক্তিগত স্ট্যাটিক ক্ষেত্র এবং থ্রেডের অভ্যন্তরে এর রাজ্য বজায় রাখে।

আরও পড়ুন: জাভাতে থ্রেডলোকাল - উদাহরণ প্রোগ্রাম এবং টিউটোরিয়াল


থ্রেডলোকালকে এক্সিকিউশন ট্রেস সংরক্ষণ করতে ব্যবহার করা যেতে পারে
গৌরব

11

ডকুমেন্টেশনটি এটি খুব ভালভাবে বলেছে: "প্রতিটি থ্রেড যা [একটি থ্রেড-লোকাল ভেরিয়েবল] অ্যাক্সেস করে (তার গেট বা সেট পদ্ধতির মাধ্যমে) এর নিজস্ব, ভেরিয়েবলের স্বতন্ত্রভাবে আরম্ভকৃত কপি থাকে" "

প্রতিটি থ্রেডের কোনও কিছুর নিজস্ব অনুলিপি থাকা উচিত আপনি একটি ব্যবহার করুন। ডিফল্টরূপে, ডেটা থ্রেডগুলির মধ্যে ভাগ করা হয়।


18
ডিফল্টরূপে, স্ট্যাটিক অবজেক্টস বা অবজেক্টগুলি সুস্পষ্টভাবে থ্রেডের মধ্যে দিয়ে যায় যেখানে উভয় থ্রেড একই বস্তুর রেফারেন্স রাখে, ভাগ করা হয়। কোনও থ্রেডে স্থানীয়ভাবে ঘোষিত অবজেক্টগুলি ভাগ করা হয় না (তারা থ্রেডের স্ট্যাকের স্থানীয়) শুধু এটা স্পষ্ট করতে চেয়েছিলেন।
ইয়ান ভারলি

@ আইয়ানওয়ার্লি: এটি দেখানোর জন্য ধন্যবাদ। সুতরাং আমাদের যদি ভেরিয়েবল থাকে যা মাইথ্রেড ক্লাসে ঘোষিত হয় এবং ব্যবহৃত হয়, তবে আমাদের কি সেই ক্ষেত্রে থ্রেডলোকাল দরকার? উদাহরণ: ক্লাস মাইথ্রেড প্রসারিত করে থ্রেড {স্ট্রিং বর্ণ 1; case এই ক্ষেত্রে var1 এবং var2 থ্রেডের নিজস্ব স্ট্যাকের অংশ হবে এবং এটি ভাগ করা নেই, সুতরাং আমাদের কি এই ক্ষেত্রে থ্রেডলোকাল প্রয়োজন? আমি আমার বোঝার ক্ষেত্রে সম্পূর্ণ ভুল হতে পারি, দয়া করে গাইড করুন।
জয়েশ

4
প্রতিটি থ্রেডের যদি কোনও কিছুর নিজস্ব অনুলিপি থাকতে চায় তবে কেন এটি স্থানীয়ভাবে ঘোষণা করা যায় না (যা সর্বদা থ্রেড নিরাপদ)?
suppydino008

@ sudeepdino008 আপনি সবসময় এই থ্রেডগুলি তৈরির নিয়ন্ত্রণ রাখবেন না (ওয়েবপ্যাপ ফ্রেমওয়ার্ক, থ্রেডপুল লাইব্রেরি)
জেএমেস ২৪'১৮

10

ওয়েব অ্যাপ্লিকেশন সার্ভার একটি থ্রেড পুল রাখতে ThreadLocalপারে এবং ক্লায়েন্টের প্রতিক্রিয়ার আগে একটি ভেরি অপসারণ করা উচিত, সুতরাং পরবর্তী অনুরোধের মাধ্যমে বর্তমান থ্রেডটি পুনরায় ব্যবহার করা যেতে পারে।


8

থ্রেডলোকাল ভেরিয়েবল ব্যবহার করা যেতে পারে এমন দুটি ব্যবহারের ক্ষেত্রে -
1- যখন আমাদের একটি থ্রেডের সাথে রাষ্ট্রের সংযুক্তি প্রয়োজন (যেমন, কোনও ব্যবহারকারী আইডি বা লেনদেন আইডি)। এটি সাধারণত কোনও ওয়েব অ্যাপ্লিকেশনটির সাথে ঘটে থাকে যে কোনও সার্লেলে যাওয়ার প্রতিটি অনুরোধের সাথে এটির একটি অনন্য ট্রানজেকশন আইডি যুক্ত থাকে।

// This class will provide a thread local variable which
// will provide a unique ID for each thread
class ThreadId {
    // Atomic integer containing the next thread ID to be assigned
    private static final AtomicInteger nextId = new AtomicInteger(0);

    // Thread local variable containing each thread's ID
    private static final ThreadLocal<Integer> threadId =
        ThreadLocal.<Integer>withInitial(()-> {return nextId.getAndIncrement();});

    // Returns the current thread's unique ID, assigning it if necessary
    public static int get() {
        return threadId.get();
    }
}

নোট করুন যে এখানেInitial সহ পদ্ধতিটি ল্যাম্বডা এক্সপ্রেশন ব্যবহার করে প্রয়োগ করা হয়।
2- আর একটি ব্যবহারের ক্ষেত্রে হ'ল যখন আমরা কোনও থ্রেড নিরাপদ দৃষ্টান্ত পেতে চাই এবং সিঙ্ক্রোনাইজেশনের সাথে পারফরম্যান্স ব্যয় বেশি হওয়ায় আমরা সিঙ্ক্রোনাইজেশন ব্যবহার করতে চাই না। সিম্পলডেট ফরমেট ব্যবহার করা হয় এমন একটি ক্ষেত্রে। যেহেতু সিম্পলডিটফর্ম্যাটটি থ্রেড নিরাপদ নয় তাই এটিকে থ্রেডটি নিরাপদ করার জন্য আমাদের ব্যবস্থা দিতে হবে।

public class ThreadLocalDemo1 implements Runnable {
    // threadlocal variable is created
    private static final ThreadLocal<SimpleDateFormat> dateFormat = new ThreadLocal<SimpleDateFormat>(){
        @Override
        protected SimpleDateFormat initialValue(){
            System.out.println("Initializing SimpleDateFormat for - " + Thread.currentThread().getName() );
            return new SimpleDateFormat("dd/MM/yyyy");
        }
    };

    public static void main(String[] args) {
        ThreadLocalDemo1 td = new ThreadLocalDemo1();
        // Two threads are created
        Thread t1 = new Thread(td, "Thread-1");
        Thread t2 = new Thread(td, "Thread-2");
        t1.start();
        t2.start();
    }

    @Override
    public void run() {
        System.out.println("Thread run execution started for " + Thread.currentThread().getName());
        System.out.println("Date formatter pattern is  " + dateFormat.get().toPattern());
        System.out.println("Formatted date is " + dateFormat.get().format(new Date()));
    } 

}

আমি এখনও থ্রেডলোকাল ব্যবহার করে কোনও অনন্য আইডি উত্পন্ন করতে উদাহরণস্বরূপ ব্যবহার করতে পারছি না যদি আপনার সমস্ত উদ্দেশ্য যদি একটি ইনক্রিমেন্টাল অনন্য পূর্ণসংখ্যার মান ফিরে আসে। `` `পাবলিক ক্লাস থ্রেডআইড {// পরবর্তী থ্রেড আইডি সম্বলিত পারমাণবিক পূর্ণসংখ্যা বেসরকারী স্থিতিশীল চূড়ান্তভাবে অ্যাটমিকআইন্টিজার NextId = নতুন অ্যাটমিকআইন্টিজার (0) নির্ধারিত হবে; // বর্তমান থ্রেডের অনন্য আইডি প্রদান করে, যদি প্রয়োজন হয় তা নির্ধারণ করে সরকারী স্থিতিশীল int প্রাপ্ত () next NextId..getAndIncrement () ফেরত দিন; }} `` `
ড্যাশসওয়েন

7

জাভা 8 রিলিজ হওয়ার পরে, আরম্ভ করার আরও ঘোষিত উপায় রয়েছে ThreadLocal:

ThreadLocal<Cipher> local = ThreadLocal.withInitial(() -> "init value");

জাভা 8 রিলিজ হওয়া পর্যন্ত আপনাকে নিম্নলিখিতগুলি করতে হয়েছিল:

ThreadLocal<String> local = new ThreadLocal<String>(){
    @Override
    protected String initialValue() {
        return "init value";
    }
};

তদুপরি, যদি শ্রেণীর ইনস্ট্যান্টেশন পদ্ধতি (কনস্ট্রাক্টর, ফ্যাক্টরি পদ্ধতি) ব্যবহার করা ThreadLocalহয় তবে কোনও প্যারামিটার না নিলে আপনি কেবল পদ্ধতি রেফারেন্স (জাভা 8 তে প্রবর্তিত) ব্যবহার করতে পারেন:

class NotThreadSafe {
    // no parameters
    public NotThreadSafe(){}
}

ThreadLocal<NotThreadSafe> container = ThreadLocal.withInitial(NotThreadSafe::new);

দ্রষ্টব্য: মূল্যায়ন অলস কারণ যেহেতু আপনি java.util.function.Supplierল্যাম্বদা পাশ করছেন কেবল তখনই ThreadLocal#getডাকা হয় তবে মানটির আগে মূল্যায়ন হয় না evalu


5

থ্রেডলোকাল প্যাটার্নটি সম্পর্কে আপনাকে খুব সাবধানতা অবলম্বন করতে হবে। ফিলের মতো উল্লেখযোগ্য কিছু নীচের দিক রয়েছে, তবে একটি যা উল্লেখ করা হয়নি তা হ'ল থ্রডলোকাল প্রসঙ্গটি সেট করে এমন কোডটি "পুনরায় প্রবেশকারী" নয় তা নিশ্চিত করা।

খারাপ জিনিসগুলি ঘটতে পারে যখন তথ্য সেট করে কোডটি দ্বিতীয় বা তৃতীয় বার চালিত হয় কারণ আপনার থ্রেডের তথ্যটি যখন আপনি প্রত্যাশা করেননি তখন তা পরিবর্তন করতে শুরু করতে পারে। সুতরাং থ্রেডলোকাল তথ্যটি পুনরায় সেট করার আগে সেট করা হয়নি তা নিশ্চিত হয়ে নিন।


2
কোডটি মোকাবেলায় প্রস্তুত করা হলে পুনরায় প্রবেশ করা কোনও সমস্যা নয়। প্রবেশের সময়, ভেরিয়েবলটি ইতিমধ্যে সেট করা আছে কিনা তা নোট করুন এবং প্রস্থান করার পরে, এর পূর্ববর্তী মানটি (যদি সেখানে কিছু ছিল) পুনরুদ্ধার করুন, বা এটি সরান (না থাকলে)।
সুপারক্যাট

1
@ জেফ, ডুড, আপনি লিখেছেন প্রতিটি কোডের ক্ষেত্রে এটি সত্য, কেবল ThreadLocalনিদর্শন নয়। যদি আপনি করেন F(){ member=random(); F2(); write(member); }এবং এফ 2 কোনও নতুন মান সহ সদস্যকে ওভাররাইড করে, তবে অবশ্যই write(member)আপনি সম্পাদনা করা নম্বরটি আর লিখবেন না random()। এটি আক্ষরিক অর্থেই সাধারণ জ্ঞান। একইভাবে, আপনি যদি করেন F(){ F(); }, তবে আপনার অসীম লুপের সাথে gd ভাগ্য! এটি সর্বত্র সত্য এবং এটি নির্দিষ্ট নয় ThreadLocal
পেসারিয়ার

@ জেফ, কোড উদাহরণ?
পেসারিয়ার

5

কখন?

যখন কোনও বস্তু থ্রেড-নিরাপদ নয়, সিঙ্ক্রোনাইজেশনের পরিবর্তে যা স্কেলিবিলিটি বাধাগ্রস্থ করে, প্রতিটি থ্রেডকে একটি করে বস্তু দিন এবং এটি থ্রেডের সুযোগ রাখুন, যা থ্রেডলোকাল। বেশিরভাগ ক্ষেত্রে ব্যবহৃত তবে থ্রেড-নিরাপদ অবজেক্টগুলির মধ্যে একটি হ'ল ডেটাবেস সংযোগ এবং জেএমএস সংযোগ।

কীভাবে?

একটি উদাহরণ হ'ল বসন্ত কাঠামো থ্রেডলোকাল ভেরিয়েবলগুলিতে এই সংযোগের জিনিসগুলি রেখে পর্দার আড়ালে লেনদেন পরিচালনার জন্য থ্রেডলোকালকে প্রচুর ব্যবহার করে। উচ্চ স্তরে, যখন কোনও লেনদেন শুরু হয় এটি সংযোগ পায় (এবং স্বয়ংক্রিয় প্রতিশ্রুতি অক্ষম করে) এবং থ্রেডলোকলে রাখে। পরবর্তী ডিবি কল এ এটি ডিবি সাথে যোগাযোগের জন্য একই সংযোগ ব্যবহার করে। শেষে, এটি থ্রেডলোকাল থেকে সংযোগ গ্রহণ করে এবং লেনদেনের প্রতিশ্রুতি দেয় (বা রোলব্যাক) এবং সংযোগটি প্রকাশ করে।

আমি মনে করি লগ 4 জে এমডিসি বজায় রাখার জন্য থ্রেডলোকালও ব্যবহার করে।


5

ThreadLocal দরকারী, যখন আপনি কিছু স্থিতি রাখতে চান যা বিভিন্ন থ্রেডের মধ্যে ভাগ করা উচিত নয় তবে এটি পুরো জীবনকালে প্রতিটি থ্রেড থেকে অ্যাক্সেসযোগ্য হওয়া উচিত।

উদাহরণস্বরূপ, একটি ওয়েব অ্যাপ্লিকেশনটি কল্পনা করুন, যেখানে প্রতিটি অনুরোধটি আলাদা থ্রেড দ্বারা পরিবেশন করা হয়। কল্পনা করুন যে প্রতিটি অনুরোধের জন্য আপনার একাধিকবার ডেটা টুকরো দরকার যা গণনা করা বেশ ব্যয়বহুল। তবে, প্রতিটি ইনকামিং অনুরোধের জন্য সেই ডেটা পরিবর্তিত হতে পারে, যার অর্থ আপনি একটি সরল ক্যাশে ব্যবহার করতে পারবেন না। এই সমস্যার একটি সহজ, দ্রুত সমাধান ThreadLocalহ'ল এই ডেটাতে একটি ভেরিয়েবল হোল্ড অ্যাক্সেস থাকতে হবে, যাতে প্রতিটি অনুরোধের জন্য আপনাকে একবারেই এটি গণনা করতে হবে। অবশ্যই, এই সমস্যাটি ব্যবহার না করেও সমাধান করা যেতে পারে ThreadLocal, তবে আমি এটি উদাহরণের উদ্দেশ্যে তৈরি করেছি।

এটি বলেছিল, মনে রাখবেন যে ThreadLocalএসগুলি মূলত বৈশ্বিক রাষ্ট্রের একটি রূপ। ফলস্বরূপ, এটির অন্যান্য অনেকগুলি প্রভাব রয়েছে এবং অন্যান্য সমস্ত সম্ভাব্য সমাধান বিবেচনা করার পরেই এটি ব্যবহার করা উচিত।


থ্রেডলোকালগুলি বৈশ্বিক রাষ্ট্র না হলে আপনি এটিকে বিশ্বরাষ্ট্র হিসাবে তৈরি করেন না। এগুলি ব্যবহারিকভাবে সর্বদা অ্যাক্সেসযোগ্য স্ট্যাক সংস্থান। আপনার সমস্ত পদ্ধতিতে (যা পিছিয়ে দেওয়া হয়) কেবল সেই পরিবর্তনশীলটি পাস করার মাধ্যমে আপনি থ্রেড স্থানীয় অনুকরণ করতে পারেন; এটি বিশ্বব্যাপী রাষ্ট্র করে না ...
এনারসিসিও

এটি কোডের যে কোনও জায়গা থেকে (একই থ্রেডের প্রসঙ্গে) এই অর্থে বিশ্বব্যাপী রাষ্ট্রের একটি রূপ। এটি সমস্ত প্রতিক্রিয়াগুলির সাথে আসে, যেমন এই মানটি কে পড়েন এবং লিখেন সে সম্পর্কে যুক্তি করতে সক্ষম হচ্ছেন না। একটি ফাংশন প্যারামিটার ব্যবহার একটি retarded জিনিস নয়, এটি পরিষ্কার ইন্টারফেসের প্রচার করার জন্য একটি ভাল অনুশীলন। তবে আমি আপনার সাথে একমত যে আপনার কোডবেসের পুরো গভীরতা জুড়ে একটি প্যারামিটারটি পাস করা কোডের গন্ধ। তবে, আমি আরও বিশ্বাস করি যে অনেক ক্ষেত্রে থ্রেডলোকালের ব্যবহার হ'ল প্রথমে একটি কোডের গন্ধ যা আপনাকে এখানে নিয়ে গেছে, সুতরাং এটিই পুনর্বিবেচনা করা উচিত।
ডিমোস

এটি কেবল অবজেক্ট স্টেটের অংশ হতে পারে, বিশ্বব্যাপী এটি ব্যবহার করতে হবে না। অবশ্যই, আপনি সামান্য সামান্য ওভারহেড পাবেন, তবে একাধিক বস্তুর যদি প্রতিটি থ্রেডে পৃথক অবস্থা থাকতে হয় তবে আপনি ThreadLocalঅবজেক্ট ক্ষেত্র হিসাবে ব্যবহার করতে পারেন ...
এনারসিসিও

তুমি ঠিক বলছো. আমি সম্ভবত বেশিরভাগ অপব্যবহারের কারণে হোঁচট খেয়েছি ThreadLocal, যেখানে এটি বিশ্বব্যাপী অ্যাক্সেসযোগ্য ছিল। যেমনটি আপনি বলেছেন, এটি দৃশ্যমানতা সীমাবদ্ধ করে এখনও শ্রেণিকক্ষ হিসাবে ব্যবহার করা যেতে পারে।
ডিমোস

4

এখানে সত্যিই নতুন কিছু নয়, তবে আমি আজ আবিষ্কার করেছি যে ThreadLocalকোনও ওয়েব অ্যাপ্লিকেশনটিতে বিনের বৈধকরণ ব্যবহার করার সময় এটি খুব কার্যকর। বৈধতা বার্তা স্থানীয়, কিন্তু ডিফল্ট ব্যবহার দ্বারা Locale.getDefault()। আপনি এটির Validatorসাথে অন্যটি কনফিগার করতে পারেন MessageInterpolator, তবে Localeকখন ফোন করবেন তা নির্দিষ্ট করার কোনও উপায় নেই validate। সুতরাং আপনি একটি স্ট্যাটিক তৈরি করতে পারেন ThreadLocal<Locale>(বা এখনও আরও ভাল, আপনার প্রয়োজন হতে পারে এমন অন্যান্য জিনিসগুলির সাথে একটি সাধারণ ধারক ThreadLocalএবং তারপরে আপনার কাস্টমটি MessageInterpolatorবেছে নিতে পারেন Locale। পরবর্তী পদক্ষেপটি ServletFilterএকটি সেশন মান ব্যবহার করে এমন একটি লিখন বা request.getLocale()লোকেল এবং স্টোর সংগ্রহ করতে হবে এটা আপনার ThreadLocalরেফারেন্সে।


4

@ অজ্ঞাত (গুগল) দ্বারা যেমন উল্লেখ করা হয়েছিল, এর ব্যবহার হ'ল একটি বৈশ্বিক পরিবর্তনশীল সংজ্ঞায়িত করতে যেখানে রেফারেন্সকৃত মান প্রতিটি থ্রেডে অনন্য হতে পারে। এটি ব্যবহারের ক্ষেত্রে সাধারণত প্রবাহের বর্তমান থ্রেডের সাথে যুক্ত কিছু প্রাসঙ্গিক তথ্য সংরক্ষণ করা হয়।

জাভা EE সচেতন নয় এমন ক্লাসগুলিতে ব্যবহারকারীর পরিচয় দেওয়ার জন্য আমরা এটি একটি জাভা EE পরিবেশে ব্যবহার করি (এইচটিটিপিএসশন, বা ইজেবি সেশনকন্টেক্সট অ্যাক্সেস নেই)। এই পদ্ধতিটি, যা সুরক্ষা ভিত্তিক ক্রিয়াকলাপগুলির জন্য পরিচয় ব্যবহার করে, প্রতিটি পদ্ধতি কলটিতে স্পষ্টতই এটি পাস না করে যে কোনও জায়গা থেকে পরিচয়টি অ্যাক্সেস করতে পারে।

বেশিরভাগ জাভা EE কলগুলির ক্রিয়াকলাপের অনুরোধ / প্রতিক্রিয়া চক্র এই ধরণের ব্যবহারকে সহজ করে তোলে কারণ এটি থ্রেডলোকাল সেট এবং আনসেট করতে ভাল সংজ্ঞায়িত এন্ট্রি এবং প্রস্থান পয়েন্ট দেয়।


4

থ্রেডলোকাল নন সিঙ্ক্রোনাইজ পদ্ধতিতে একাধিক থ্রেড দ্বারা বিভাজ্য অবজেক্টটি অ্যাক্সেস নিশ্চিত করবে, যার অর্থ মিউটলেবল অবজেক্টটি পদ্ধতির মধ্যে অপরিবর্তনীয় হতে পারে।

প্রতিটি থ্রেডে এটির অ্যাক্সেসের চেষ্টা করার জন্য পরিবর্তনীয় অবজেক্টের নতুন উদাহরণ দিয়ে এটি অর্জন করা হয়েছে। সুতরাং এটি প্রতিটি থ্রেডে স্থানীয় অনুলিপি। এটি স্থানীয় ভেরিয়েবলের মতো অ্যাক্সেস করার পদ্ধতিতে উদাহরণ পরিবর্তনযোগ্য তৈরির ক্ষেত্রে কিছুটা হ্যাক। আপনি যেমন সচেতন পদ্ধতি হিসাবে স্থানীয় পরিবর্তনশীল কেবল থ্রেডের জন্য উপলব্ধ, তবে একটি পার্থক্য; থ্রেডলোকালের সাথে ভাগ করা মিউটটেবল অবজেক্টটি যতক্ষণ না আমরা এটি পরিষ্কার করি ততক্ষণ একাধিক পদ্ধতিতে থ্রিডলোকলের সাথে ভাগ করা পরিবর্তনীয় অবজেক্টটি উপস্থিত হয়ে গেলে পদ্ধতি স্থানীয় ভেরিয়েবলগুলি থ্রেডে উপলভ্য হবে না।

সংজ্ঞানুসারে:

জাভার থ্রেডলোকাল ক্লাস আপনাকে এমন ভেরিয়েবলগুলি তৈরি করতে সক্ষম করে যা কেবল একই থ্রেড দ্বারা পড়া এবং লেখা যায় written সুতরাং, এমনকি যদি দুটি থ্রেড একই কোডটি চালাচ্ছে এবং কোডটিতে একটি থ্রেডলোকাল ভেরিয়েবলের উল্লেখ রয়েছে, তবে দুটি থ্রেড একে অপরের থ্রেডলোকাল ভেরিয়েবলগুলি দেখতে পাবে না।

Threadজাভা প্রতিটি এটিতে থাকে ThreadLocalMap
কোথায়

Key = One ThreadLocal object shared across threads.
value = Mutable object which has to be used synchronously, this will be instantiated for each thread.

থ্রেডলোকাল অর্জন করা:

এখন থ্রেডলোকালের জন্য একটি মোড়কের ক্লাস তৈরি করুন যা নীচের (যেমন বা বাইরে initialValue()) মত পরিবর্তনীয় বস্তুটি ধরে রাখতে চলেছে ।
এখন এই র‍্যাপারটির গেটর এবং সেটার মিউটেটেবল অবজেক্টের পরিবর্তে থ্রেডলোকাল ইনসেস্টে কাজ করবে।

থ্রেডলোকালের গেটার যদি () এর থ্রেডলোক্যাল্যাপের সাথে কোনও মান খুঁজে না পায় Thread; তারপরে এটি থ্রেডের সাথে সম্মতভাবে তার ব্যক্তিগত অনুলিপি পেতে প্রাথমিক মান () কে অনুরোধ করবে।

class SimpleDateFormatInstancePerThread {

    private static final ThreadLocal<SimpleDateFormat> dateFormatHolder = new ThreadLocal<SimpleDateFormat>() {

        @Override
        protected SimpleDateFormat initialValue() {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd") {
                UUID id = UUID.randomUUID();
                @Override
                public String toString() {
                    return id.toString();
                };
            };
            System.out.println("Creating SimpleDateFormat instance " + dateFormat +" for Thread : " + Thread.currentThread().getName());
            return dateFormat;
        }
    };

    /*
     * Every time there is a call for DateFormat, ThreadLocal will return calling
     * Thread's copy of SimpleDateFormat
     */
    public static DateFormat getDateFormatter() {
        return dateFormatHolder.get();
    }

    public static void cleanup() {
        dateFormatHolder.remove();
    }
}

এখন wrapper.getDateFormatter()ডাকব threadlocal.get()এবং যে চেক করবে currentThread.threadLocalMapধারণ করে এই (threadlocal) উদাহরণস্বরূপ।
যদি হ্যাঁ সংশ্লিষ্ট থ্রেডলোকাল দৃষ্টান্তের জন্য মান (সিম্পলডেট ফরমেট) ফেরান
তবে অন্যথায় এই থ্রডলোকাল উদাহরণ, ইনিশিয়ালভ্যালু () সহ মানচিত্র যুক্ত করুন।

এর সাথে এই পরিবর্তনীয় শ্রেণিতে থ্রেড সুরক্ষা অর্জন করা হয়েছে; প্রতিটি থ্রেড তার নিজস্ব পরিবর্তনীয় উদাহরণ সহ একই থ্রেডলোকাল উদাহরণ সহ কাজ করছে। মানে সমস্ত থ্রেড কী হিসাবে একই থ্রেডলোকাল উদাহরণটি ভাগ করে নেবে, তবে মান হিসাবে বিভিন্ন সরলডেট ফরমেট উদাহরণটি।

https://github.com/skanagavelu/yt.tech/blob/master/src/ThreadLocalTest.java


3

থ্রেড-লোকাল ভেরিয়েবলগুলি প্রায়শই পরিবর্তিত সিঙ্গললেট বা গ্লোবাল ভেরিয়েবলের উপর ভিত্তি করে ডিজাইনে ভাগ করা রোধ করতে ব্যবহৃত হয়।

আপনি যখন কোনও সংযোগ পুল ব্যবহার করছেন না তখন এটি প্রতিটি থ্রেডের জন্য পৃথক জেডিবিসি সংযোগ তৈরি করার মতো পরিস্থিতিতে ব্যবহার করা যেতে পারে।

private static ThreadLocal<Connection> connectionHolder
           = new ThreadLocal<Connection>() {
      public Connection initialValue() {
           return DriverManager.getConnection(DB_URL);
          }
     };

public static Connection getConnection() {
      return connectionHolder.get();
} 

আপনি যখন getConnection কল করবেন, তখন এটি সেই থ্রেডের সাথে যুক্ত একটি সংযোগ ফিরিয়ে দেবে date এটি ডেট ফর্ম্যাট, লেনদেন প্রসঙ্গে যেমন অন্য বৈশিষ্ট্যগুলির সাথেও করা যেতে পারে যা আপনি থ্রেডগুলির মধ্যে ভাগ করতে চান না।

আপনি এটির জন্য স্থানীয় ভেরিয়েবলগুলিও ব্যবহার করতে পারতেন তবে এই সংস্থানগুলি সাধারণত সৃষ্টিতে সময় নেয়, তাই আপনি যখনই তাদের সাথে কিছু ব্যবসায়িক যুক্তি সম্পাদন করেন আপনি বার বার এগুলি তৈরি করতে চান না। তবে থ্রেডলোকাল মানগুলি থ্রেড অবজেক্টে নিজেই সংরক্ষণ করা হয় এবং থ্রেডটি আবর্জনা সংগ্রহ করার সাথে সাথে এই মানগুলিও চলে যায়।

এই লিঙ্কটি থ্রেডলোকালের ব্যবহার খুব ভালভাবে ব্যাখ্যা করে।


2
এই উদাহরণে একটি বড় সমস্যা: সংযোগটি বন্ধ করার জন্য কে দায়ী? প্রাথমিকভাবে মান হিসাবে এই সংযোগটি তৈরি করার পরিবর্তে, সংযোগের গ্রাহক স্পষ্টভাবে সংযোগটি তৈরি করতে দিন এবং থ্রেডলোকালের মাধ্যমে থ্রেডে আবদ্ধ করুন। সংযোগের স্রষ্টা তখন বন্ধ করার জন্যও দায়বদ্ধ। এটি এই উদাহরণে পরিষ্কার নয়। সংযোগ তৈরি এবং বাঁধাই ট্রানজেকশন.বেগিন () এবং ট্রানজেকশন.েন্ড () এর মতো কিছু দ্বারা একটি সাধারণ কাঠামোর মধ্যেও লুকানো যেতে পারে।
রিক-রেইনার লুডভিগ

2

ThreadLocal জাভা শ্রেণী আপনি ভেরিয়েবল যে শুধুমাত্র পাঠযোগ্য এবং একই থ্রেড লিখতে পারবেন তৈরি করতে সক্ষম করে। সুতরাং, এমনকি যদি দুটি থ্রেড একই কোডটি চালাচ্ছে এবং কোডটিতে একটি থ্রেডলোকাল ভেরিয়েবলের উল্লেখ রয়েছে, তবে দুটি থ্রেড একে অপরের থ্রেডলোকাল ভেরিয়েবলগুলি দেখতে পাবে না।

আরও পড়ুন


2

মাল্ট্রিথ্রেড কোডে সিম্পলডেট ফরমেটের মতো শ্রেণি সহায়ক ব্যবহার করার জন্য 3 টি পরিস্থিতি রয়েছে , যা থ্রেডলোকাল সেরা ব্যবহার করে

প্রেক্ষাপটে

1- লক বা সিঙ্ক্রোনাইজেশন প্রক্রিয়ার সাহায্যে লাইক শেয়ার অবজেক্ট ব্যবহার করা যা অ্যাপ্লিকেশনটিকে ধীর করে তোলে

2- একটি পদ্ধতির অভ্যন্তরে স্থানীয় অবজেক্ট হিসাবে ব্যবহার করা

এই দৃশ্যে , যদি আমাদের 4 টি থ্রেড থাকে তবে প্রত্যেকে 1000 বার একটি পদ্ধতি কল করে তারপরে আমাদের
4000 সিম্পলডেটফর্ম্যাট অবজেক্ট তৈরি হয়েছে এবং জিসি সেগুলি মুছে ফেলার জন্য অপেক্ষা করছে

3- থ্রেডলোকাল ব্যবহার করে

যদি আমাদের 4 টি থ্রেড থাকে এবং আমরা প্রতিটি থ্রেডকে একটি করে সিম্পলডেট ফরমেট উদাহরণ দিয়েছি
যাতে আমাদের 4 টি থ্রেড , সরলডেট ফরমেটের 4 টি অবজেক্ট রয়েছে।

লক প্রক্রিয়া এবং অবজেক্ট তৈরি এবং ধ্বংসের প্রয়োজন নেই। (শুভ সময় জটিলতা এবং স্পেস জটিলতা)


2

[রেফারেন্সের জন্য] থ্রেডলোকল শেয়ার্ড অবজেক্টের আপডেট সমস্যাগুলি সমাধান করতে পারে না। এটি একটি স্ট্যাটিক ট্র্যাডলোকাল অবজেক্ট ব্যবহার করার পরামর্শ দেওয়া হয় যা একই থ্রেডে সমস্ত ক্রিয়াকলাপ দ্বারা ভাগ করা হয়। [বাধ্যতামূলক] অপসারণ () পদ্ধতিটি অবশ্যই থ্রেডলোকাল ভেরিয়েবল দ্বারা প্রয়োগ করা উচিত, বিশেষত থ্রেড পুল ব্যবহার করার সময় যেখানে থ্রেড প্রায়শই পুনরায় ব্যবহার করা হয়। অন্যথায়, এটি পরবর্তী ব্যবসায়ের যুক্তিগুলিকে প্রভাবিত করতে পারে এবং মেমরি ফাঁস হওয়ার মতো অপ্রত্যাশিত সমস্যার কারণ হতে পারে।


1

ক্যাশিং, কোনও সময় আপনাকে একই মান প্রচুর পরিমাণে গণনা করতে হবে যাতে কোনও পদ্ধতিতে ইনপুটগুলির শেষ সেটটি সংরক্ষণ করে ফলাফলটি আপনি কোডটি গতিতে করতে পারেন। থ্রেড লোকাল স্টোরেজ ব্যবহার করে আপনি লক করার বিষয়ে ভাবেন না avoid


1

থ্রেডলোকালটি কেবল থ্রেডগুলির জন্য পৃথক পৃথক স্টোরেজ স্পেস সরবরাহের জন্য জেভিএম দ্বারা একটি বিশেষভাবে সরবরাহিত কার্যকারিতা। উদাহরণস্বরূপ স্কোপড ভেরিয়েবলের মানটি কেবল একটি শ্রেণীর প্রদত্ত উদাহরণের সাথে আবদ্ধ। প্রতিটি বস্তুর একমাত্র মান রয়েছে এবং তারা একে অপরের মান দেখতে পারে না। থ্রেডলোকাল ভেরিয়েবলের ধারণাটিও একই, তারা বস্তুর দৃষ্টিকোণে থ্রেডে স্থানীয়, অন্য থ্রেড যা তৈরি করেছে, তা দেখতে পারা যায় না। এখানে দেখো

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


public class ThreadId {
private static final AtomicInteger nextId = new AtomicInteger(1000);

// Thread local variable containing each thread's ID
private static final ThreadLocal<Integer> threadId = ThreadLocal.withInitial(() -> nextId.getAndIncrement());


// Returns the current thread's unique ID, assigning it if necessary
public static int get() {
    return threadId.get();
}

public static void main(String[] args) {

    new Thread(() -> IntStream.range(1, 3).forEach(i -> {
        System.out.println(Thread.currentThread().getName() + " >> " + new ThreadId().get());
    })).start();

    new Thread(() -> IntStream.range(1, 3).forEach(i -> {
        System.out.println(Thread.currentThread().getName() + " >> " + new ThreadId().get());
    })).start();

    new Thread(() -> IntStream.range(1, 3).forEach(i -> {
        System.out.println(Thread.currentThread().getName() + " >> " + new ThreadId().get());
    })).start();

}
}

1

থ্রেডলোকাল শূন্য ব্যয় সহ বস্তুর পুনঃব্যবহারযোগ্যতা অর্জনের জন্য খুব সহজ উপায় সরবরাহ করে।

আমার এমন এক পরিস্থিতি ছিল যেখানে প্রতিটি আপডেটের বিজ্ঞপ্তিতে একাধিক থ্রেড মিউটেটেবল ক্যাশে একটি চিত্র তৈরি করে।

আমি প্রতিটি থ্রেডে একটি থ্রেডলোকাল ব্যবহার করেছি এবং তারপরে প্রতিটি থ্রেডকে পুরানো চিত্রটি পুনরায় সেট করতে হবে এবং তারপরে প্রতিটি আপডেটের বিজ্ঞপ্তিতে ক্যাশে থেকে আবার এটি আপডেট করতে হবে।

অবজেক্ট পুলগুলি থেকে সাধারণ পুনরায় ব্যবহারযোগ্য বস্তুর সাথে থ্রেড সুরক্ষা ব্যয় যুক্ত থাকে, যদিও এই পদ্ধতির কোনও নেই।


0

থ্রেডলোকাল ভেরিয়েবলের অনুভূতি পেতে এই ছোট্ট উদাহরণটি ব্যবহার করে দেখুন:

public class Book implements Runnable {
    private static final ThreadLocal<List<String>> WORDS = ThreadLocal.withInitial(ArrayList::new);

    private final String bookName; // It is also the thread's name
    private final List<String> words;


    public Book(String bookName, List<String> words) {
        this.bookName = bookName;
        this.words = Collections.unmodifiableList(words);
    }

    public void run() {
        WORDS.get().addAll(words);
        System.out.printf("Result %s: '%s'.%n", bookName, String.join(", ", WORDS.get()));
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new Book("BookA", Arrays.asList("wordA1", "wordA2", "wordA3")));
        Thread t2 = new Thread(new Book("BookB", Arrays.asList("wordB1", "wordB2")));
        t1.start();
        t2.start();
    }
}


কনসোল আউটপুট, থ্রেড BookA প্রথমে সম্পন্ন হলে:
ফলাফল BookA: 'wordA1, wordA2, wordA3'।
ফলাফল বুকবি: 'ওয়ার্ডবি 1, ওয়ার্ডবি 2'।

কনসোল আউটপুট, থ্রেড বুকবি যদি প্রথমে করা হয়:
ফলাফল বুকবি: 'ওয়ার্ডবি 1, ওয়ার্ডবি 2'।
ফলাফল BookA: 'wordA1, wordA2, wordA3'।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.