জাভাতে অস্থির এবং সিঙ্ক্রোনাইজের মধ্যে পার্থক্য


233

আমি ভেরিয়েবল হিসাবে volatileঘোষিত হওয়া synchronized(this)এবং জাভাতে কোনও ব্লকে সর্বদা ভেরিয়েবল অ্যাক্সেস করার মধ্যে পার্থক্যটি নিয়ে ভাবছি ?

এই নিবন্ধটি অনুসারে http://www.javamex.com / টিউটোরিয়ালস / সিনক্রোনাইজেশন_ভোটাটাইল.শটিটিএমএল অনেক কিছু বলা যায় এবং বিভিন্ন পার্থক্য রয়েছে তবে কিছু মিলও রয়েছে।

আমি এই তথ্যের টুকরোটিতে বিশেষত আগ্রহী:

...

  • একটি উদ্বায়ী ভেরিয়েবলের অ্যাক্সেসে ব্লক হওয়ার সম্ভাবনা থাকে না: আমরা কেবল কখনও সরল পড়া বা লেখার কাজ করে যাচ্ছি, তাই সিঙ্ক্রোনাইজড ব্লকের বিপরীতে আমরা কখনই কোনও লক ধরে থাকব না;
  • যেহেতু একটি অস্থির পরিবর্তনশীল অ্যাক্সেসে কোনও লক থাকে না, এটি এমন ক্ষেত্রে উপযুক্ত নয় যেখানে আমরা পারমাণবিক ক্রিয়াকলাপ হিসাবে পড়া-আপডেট-লিখতে চাই (যদি না আমরা "একটি আপডেট মিস করতে প্রস্তুত না");

পড়া-আপডেট-লেখার দ্বারা তারা কী বোঝায় ? একটি লিখনও কি আপডেট নয় বা এগুলি কি সহজভাবে বোঝায় যে আপডেটটি এমন একটি লেখা যা পড়ার উপর নির্ভর করে?

সর্বোপরি, volatileকোনও synchronizedব্লকের মাধ্যমে অ্যাক্সেস করার পরিবর্তে ভেরিয়েবলগুলি ঘোষণা করা আরও উপযুক্ত কখন ? volatileইনপুটের উপর নির্ভরশীল ভেরিয়েবলগুলির জন্য ব্যবহার করা কি ভাল ধারণা ? উদাহরণস্বরূপ, একটি ভেরিয়েবল বলা renderহয় যা রেন্ডারিং লুপের মাধ্যমে পড়ে এবং কী কী চাপুন ইভেন্ট দ্বারা সেট করা হয়?

উত্তর:


383

এটি বোঝা গুরুত্বপূর্ণ যে থ্রেড সুরক্ষার দুটি দিক রয়েছে।

  1. সম্পাদন নিয়ন্ত্রণ, এবং
  2. মেমরি দৃশ্যমানতা

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

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

volatileঅন্যদিকে, ব্যবহার করে সমস্ত অ্যাক্সেসগুলি (পড়ুন বা লিখুন )টিকে অস্থির ভেরিয়েবলের মূল স্মৃতিতে ঘটতে বাধ্য করে, কার্যকরভাবে অস্থির ভেরিয়েবলকে সিপিইউ ক্যাশের বাইরে রাখে। এটি কিছু ক্রিয়াকলাপের জন্য দরকারী হতে পারে যেখানে ভেরিয়েবলের দৃশ্যমানতা সঠিক হওয়া এবং অ্যাক্সেসের ক্রমটি গুরুত্বপূর্ণ নয় required ব্যবহার volatileএছাড়াও চিকিত্সার পরিবর্তন longএবং doubleপারমাণবিক হতে তাদের ব্যবহারের প্রয়োজন; কিছু (পুরানো) হার্ডওয়্যারে এটি লক প্রয়োজন হতে পারে, যদিও আধুনিক modern৪ বিট হার্ডওয়ারে নেই। জাভা 5+ এর জন্য নতুন (জেএসআর -133) মেমরি মডেলের অধীনে, অস্থিরতার শব্দার্থকে মেমরির দৃশ্যমানতা এবং নির্দেশের আদেশের সাথে সম্মতিযুক্ত প্রায় ততই শক্তিশালী করার জন্য শক্তিশালী করা হয়েছে (দেখুন http://www.cs.umd.edu /users/pugh/java/memoryModel/jsr-133-faq.html#volatile)। দৃশ্যমানতার উদ্দেশ্যে, একটি অস্থির ক্ষেত্রের প্রতিটি অ্যাক্সেস অর্ধ সিঙ্ক্রোনাইজের মতো কাজ করে।

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

- জেএসআর 133 (জাভা মেমোরি মডেল) FAQ

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

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

// Declaration
public class SharedLocation {
    static public SomeObject someObject=new SomeObject(); // default object
    }

// Publishing code
// Note: do not simply use SharedLocation.someObject.xxx(), since although
//       someObject will be internally consistent for xxx(), a subsequent 
//       call to yyy() might be inconsistent with xxx() if the object was 
//       replaced in between calls.
SharedLocation.someObject=new SomeObject(...); // new object is published

// Using code
private String getError() {
    SomeObject myCopy=SharedLocation.someObject; // gets current copy
    ...
    int cod=myCopy.getErrorCode();
    String txt=myCopy.getErrorText();
    return (cod+" - "+txt);
    }
// And so on, with myCopy always in a consistent state within and across calls
// Eventually we will return to the code that gets the current SomeObject.

আপনার পঠন-আপডেট-লেখার প্রশ্নে বিশেষভাবে কথা বলছেন। নিম্নলিখিত অনিরাপদ কোডটি বিবেচনা করুন:

public void updateCounter() {
    if(counter==1000) { counter=0; }
    else              { counter++; }
    }

এখন, আপডেটকৌনটার () পদ্ধতিটি আনসক্রোনাইজড দিয়ে দুটি থ্রেড একই সাথে এটি প্রবেশ করতে পারে। যা ঘটতে পারে তার অনেকগুলি অনুমতিগুলির মধ্যে একটি হ'ল থ্রেড -1 পরীক্ষার জন্য == 1000 পরীক্ষা করে এবং এটি সত্য বলে মনে হয় এবং তারপরে স্থগিত করা হয়। তারপরে থ্রেড -2 একই পরীক্ষা করে এবং এটি সত্যও দেখায় এবং স্থগিত করা হয়। তারপরে থ্রেড -1 পুনরায় শুরু হয় এবং 0 এর বিপরীতে সেট করে Then তারপরে থ্রেড -2 পুনরায় শুরু হয় এবং আবার 0 টির সাথে কাউন্টার সেট করে কারণ এটি থ্রেড -1 থেকে আপডেটটি মিস করেছে। থ্রেড স্যুইচিং না ঘটলে এমনকি ঘটতে পারে যেমনটি আমি বর্ণনা করেছি, তবে কেবলমাত্র দুটি পৃথক সিপিইউ কোরে কাউন্টারের দুটি পৃথক ক্যাশে অনুলিপি উপস্থিত ছিল এবং থ্রেডগুলি পৃথক পৃথক কোরে চলেছে। এই বিষয়টির জন্য, একটি থ্রেডের একটি মানতে কাউন্টার থাকতে পারে এবং অন্যটিতে কেবল ক্যাশে দেওয়ার কারণে কিছু সম্পূর্ণ ভিন্ন মানের পাল্টা থাকতে পারে।

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

MOV EAX,counter
INC EAX
MOV counter,EAX

উদ্বায়ী ভেরিয়েবলগুলি কেবল তখন কার্যকর হয় যখন তাদের উপর সঞ্চালিত সমস্ত ক্রিয়াকলাপগুলি "পারমাণবিক" হয়, যেমন আমার উদাহরণ যেখানে সম্পূর্ণরূপে গঠিত বস্তুর উল্লেখ কেবল পঠিত বা লিখিত হয় (এবং প্রকৃতপক্ষে, সাধারণত এটি কেবলমাত্র একটি বিন্দু থেকে লেখা হয়)। আর একটি উদাহরণ হ'ল একটি অস্থির অ্যারে রেফারেন্স যা অনুলিপি-অনুলিপি তালিকার ব্যাক করে, তবে শর্তটি কেবল রেফারেন্সের স্থানীয় কপি নিয়ে প্রথমে পড়তে হবে।


5
অনেক ধন্যবাদ! কাউন্টার সহ উদাহরণটি বোঝা সহজ। যাইহোক, জিনিসগুলি বাস্তব হয়ে উঠলে এটি কিছুটা আলাদা।
অ্যালবাস ডাম্বলডোর

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

1
@ শনিম এটি এক নয়, তবে এতে জড়িত থ্রেডগুলির স্থানীয় ক্যাশে অন্তর্ভুক্ত থাকবে। ।
লরেন্স ডল

1
@ মেরিয়ানপাডজিওচ: একটি বৃদ্ধি বা হ্রাস কোনও পাঠ বা লিখন নয়, এটি একটি পঠন এবং একটি লেখা; এটি একটি রেজিস্টারে একটি পঠন, তারপরে একটি রেজিস্টার বৃদ্ধি, তারপরে স্মৃতিতে একটি লেখা। পড়া এবং লেখাগুলি স্বতন্ত্রভাবে পারমাণবিক, তবে একাধিক এ জাতীয় অপারেশন হয় না।
লরেন্স ডল

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

97

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

    int i1;
    int geti1() {return i1;}

    volatile int i2;
    int geti2() {return i2;}

    int i3;
    synchronized int geti3() {return i3;}

geti1()i1বর্তমান থ্রেডে বর্তমানে সঞ্চিত মান অ্যাক্সেস করে । থ্রেডগুলিতে ভেরিয়েবলের স্থানীয় অনুলিপি থাকতে পারে এবং অন্যান্য থ্রেডে থাকা ডেটার মতো ডেটা একইরকম হতে হবে না particular বিশেষত, অন্য থ্রেডটি i1এর থ্রেডে আপডেট হতে পারে , তবে বর্তমান থ্রেডের মান এর থেকে আলাদা হতে পারে thread আপডেট মান। প্রকৃতপক্ষে জাভাতে একটি "প্রধান" মেমরির ধারণা রয়েছে এবং এটি সেই মেমরিটি যা চলকগুলির জন্য বর্তমান "সঠিক" মান ধারণ করে। থ্রেডগুলির ভেরিয়েবলগুলির জন্য ডেটাগুলির নিজস্ব অনুলিপি থাকতে পারে এবং থ্রেড অনুলিপি "প্রধান" মেমরির থেকে পৃথক হতে পারে। তাই আসলে, এটি সম্ভব "মেন" মেমরি একটি মান আছে জন্য 1 জন্য i1thread1 একটি মূল্য আছে জন্য, 2 জন্য i1এবং জন্য thread2মান আছে 3 উভয় আপডেট i1 কিন্তু যারা আপডেট মান এখনো "মেন" মেমরি বা অন্যান্য থ্রেড প্রচারিত হয় নি আছে।জন্য i1যদি thread1 এবং thread2

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

ভোলিটাইল এবং সিঙ্ক্রোনাইজডের মধ্যে দুটি পার্থক্য রয়েছে।

প্রথমে সিঙ্ক্রোনাইজ করা মনিটরগুলিতে লকগুলি রিলিজ করে এবং প্রকাশ করে যা একটি সময়ে ব্লক কার্যকর করতে কেবল একটি থ্রেডকে বাধ্য করতে পারে। এটি সিঙ্ক্রোনাইজ করার জন্য মোটামুটি সুপরিচিত দিক। কিন্তু সিঙ্ক্রোনাইজড মেমোরিটিকে সিঙ্ক্রোনাইজ করে। আসলে সিঙ্ক্রোনাইজ করা পুরো থ্রেড মেমরিটিকে "মূল" মেমরির সাথে সিঙ্ক্রোনাইজ করে। সুতরাং geti3()নিম্নলিখিতটি কার্যকর করে:

  1. থ্রেড এটির জন্য বস্তুর জন্য মনিটরে লকটি অর্জন করে।
  2. থ্রেড মেমরিটি তার সমস্ত ভেরিয়েবলগুলি ফ্লাশ করে, অর্থাত্ এটির সমস্ত ভেরিয়েবল কার্যকরভাবে "মূল" মেমরি থেকে পড়ে read
  3. কোড ব্লক কার্যকর করা হয়েছে (এক্ষেত্রে i3 এর বর্তমান মানটিতে রিটার্ন মান নির্ধারণ করে, যা সম্ভবত "প্রধান" মেমরি থেকে রিসেট হয়ে থাকতে পারে)।
  4. (ভেরিয়েবলগুলিতে যে কোনও পরিবর্তন সাধারনত এখন "মূল" মেমরিতে লেখা থাকবে, তবে গেটি 3 () এর জন্য আমাদের কোনও পরিবর্তন নেই))
  5. থ্রেড এটির জন্য বস্তুর জন্য মনিটরে লকটি প্রকাশ করে।

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

http://javaexp.blogspot.com/2007/12/difference-between-volatile-and.html


35
-1, উদ্বায়ী কোনও লক অর্জন করে না, এটি লেখার পরে সমস্ত থ্রেডে দৃশ্যমানতা নিশ্চিত করতে অন্তর্নিহিত সিপিইউ আর্কিটেকচার ব্যবহার করে।
মাইকেল বার্কার

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

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

20

synchronizedপদ্ধতি পদ্ধতি / ব্লক স্তরের অ্যাক্সেস সীমাবদ্ধতা পরিবর্তনকারী mod এটি নিশ্চিত করবে যে একটি থ্রেড সমালোচনামূলক বিভাগের জন্য লকটির মালিক। শুধুমাত্র থ্রেড, যার একটি লক রয়েছে তা synchronizedব্লক প্রবেশ করতে পারে । যদি অন্য থ্রেডগুলি এই সমালোচনামূলক বিভাগটি অ্যাক্সেস করার চেষ্টা করে থাকে তবে তাদের বর্তমান মালিক লকটি প্রকাশ না হওয়া পর্যন্ত তাদের অপেক্ষা করতে হবে।

volatileভেরিয়েবল অ্যাক্সেস মডিফায়ার যা সমস্ত থ্রেডকে মূল স্মৃতি থেকে ভেরিয়েবলের সর্বশেষ মান পেতে বাধ্য করে। volatileভেরিয়েবল অ্যাক্সেস করার জন্য কোনও লকিংয়ের প্রয়োজন নেই । সমস্ত থ্রেড একই সাথে অস্থায়ী পরিবর্তনশীল মান অ্যাক্সেস করতে পারে।

উদ্বায়ী ভেরিয়েবল ব্যবহারের জন্য একটি ভাল উদাহরণ: Dateপরিবর্তনশীল।

ধরে নিন যে আপনি তারিখ পরিবর্তনশীল করেছেন volatile। সমস্ত থ্রেড, যা এই পরিবর্তনশীল অ্যাক্সেস করে সর্বদা মূল স্মৃতি থেকে সর্বশেষতম ডেটা পায় যাতে সমস্ত থ্রেড আসল (প্রকৃত) তারিখের মানটি দেখায়। একই ভেরিয়েবলের জন্য আপনার আলাদা আলাদা থ্রেডের প্রয়োজন নেই। সমস্ত থ্রেডের সঠিক তারিখের মানটি দেখানো উচিত।

এখানে চিত্র বর্ণনা লিখুন

ধারণাটির আরও ভাল বোঝার জন্য এই নিবন্ধটি দেখুন volatile

লরেন্স ডল ক্লিয়ারি আপনার ব্যাখ্যা read-write-update query

আপনার অন্যান্য প্রশ্নের বিষয়ে

ভেরিয়েবলগুলি সিঙ্ক্রোনাইজের মাধ্যমে অ্যাক্সেস করার চেয়ে অস্থির ঘোষিত করার পক্ষে কখন উপযুক্ত?

volatileতারিখ ভেরিয়েবলের জন্য যে উদাহরণটি আমি ব্যাখ্যা করেছি তার মতো সমস্ত থ্রেডের আসল সময়ে পরিবর্তনের আসল মান পাওয়া উচিত যদি আপনি ভাবেন তবে আপনাকে ব্যবহার করতে হবে।

ইনপুট উপর নির্ভরশীল ভেরিয়েবলগুলির জন্য উদ্বায়ী ব্যবহার করা কি ভাল ধারণা?

উত্তর প্রথম ক্যোয়ারির মতো হবে।

আরও ভাল বোঝার জন্য এই নিবন্ধটি দেখুন


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

11

tl; dr :

মাল্টিথ্রেডিংয়ের সাথে 3 টি মূল সমস্যা রয়েছে:

1) রেস শর্তসমূহ

2) ক্যাশিং / বাসি স্মৃতি

3) সরবরাহকারী এবং সিপিইউ অপ্টিমাইজেশন

volatile 2 এবং 3 সমাধান করতে পারে তবে 1 টি সমাধান করতে পারে না। synchronized করতে পারে তবে 1 টি সমাধান করতে পারে না / / সুস্পষ্ট লকগুলি 1, 2 এবং 3 সমাধান করতে পারে।

বিবরণাদি :

1) এই থ্রেডটি অনিরাপদ কোডটি বিবেচনা করুন:

x++;

এটি কোনও অপারেশনের মতো দেখতে হলেও এটি আসলে 3: মেমরি থেকে এক্সের বর্তমান মান পড়া, এতে 1 যুক্ত করা এবং এটিকে মেমোরিতে ফিরিয়ে দেওয়া। যদি কয়েকটি থ্রেড একই সাথে এটি করার চেষ্টা করে তবে অপারেশনের ফলাফল অপরিবর্তিত। xমূলত যদি 1 হয়, 2 টি থ্রেডের পরে কোডটি পরিচালনা করে এটি 2 হতে পারে এবং এটি 3 হতে পারে, কোনও থ্রেড নিয়ন্ত্রণের আগে অপারেশনের কোন অংশটি অন্য থ্রেডে স্থানান্তরিত হয়েছিল তার উপর নির্ভর করে। এটি জাতি শর্তের একটি রূপ

synchronizedকোডের একটি ব্লকে ব্যবহার করা এটি পারমাণবিক করে তোলে - এর অর্থ এটি এটিকে এমনভাবে তৈরি করে যে 3 টি ক্রিয়াকলাপ একবারে ঘটে এবং এর মধ্য দিয়ে অন্য থ্রেডে এসে হস্তক্ষেপের কোনও উপায় নেই। সুতরাং যদি x1, এবং 2 থ্রেডগুলি প্রিমফ করার চেষ্টা করে তবে x++আমরা জানি শেষ পর্যন্ত এটি 3 এর সমান হবে So সুতরাং এটি রেসের শর্ত সমস্যার সমাধান করে।

synchronized (this) {
   x++; // no problem now
}

xহিসাবে চিহ্নিত করা volatileহয় নাx++; পারমাণবিক , সুতরাং এটি এই সমস্যার সমাধান করে না।

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

এক থ্রেড এ বিবেচনা করুন x = 10;,। এবং কিছুটা পরে, অন্য থ্রেডে x = 20;,। মানটির পরিবর্তনটি xপ্রথম থ্রেডে প্রদর্শিত না হতে পারে, কারণ অন্য থ্রেডটি তার কার্যকরী স্মৃতিতে নতুন মানটি সংরক্ষণ করেছে, তবে এটি মূল স্মৃতিতে অনুলিপি করেছে। বা এটি এটি মূল স্মৃতিতে অনুলিপি করেছে তবে প্রথম থ্রেডটি তার কার্যকরী অনুলিপি আপডেট করে নি। সুতরাং এখন যদি প্রথম থ্রেড চেক if (x == 20)করে উত্তর হবে false

মূল হিসাবে একটি চলক চিহ্নিত করা volatileসমস্ত থ্রেডকে কেবল প্রধান মেমরির উপর পড়া এবং লেখার কাজ করতে বলে। synchronizedপ্রতিটি থ্রেডকে বল থাকে যে তারা যখন ব্লকটিতে প্রবেশ করে তখন মূল মেমরি থেকে তাদের মান আপডেট করে এবং ব্লক থেকে প্রস্থান করার পরে ফলাফলটি মূল স্মৃতিতে ফিরে যায়।

নোট করুন যে ডেটা রেসের বিপরীতে, বাসি মেমরিটি পুনরায় তৈরি করা এত সহজ নয়, যেহেতু মূল স্মৃতিতে ফ্লাশগুলি ঘটে।

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

নিম্নলিখিত কোড বিবেচনা করুন:

boolean b = false;
int x = 10;

void threadA() {
    x = 20;
    b = true;
}

void threadB() {
    if (b) {
        System.out.println(x);
    }
}

আপনি ভাববেন যে থ্রেডবি কেবলমাত্র 20 টি মুদ্রণ করতে পারে (বা থ্রडবি যদি bসত্য হিসাবে bসেট করার আগে পরীক্ষা করা হয় তবে কিছু প্রিন্ট করতে পারে না), ঠিক x20 এ সেট করার পরে সত্য হিসাবে সেট করা থাকলেও সংকলক / সিপিইউ পুনরায় অর্ডার করার সিদ্ধান্ত নিতে পারে থ্রেডএ, সেক্ষেত্রে থ্রেডবি 10 টিও মুদ্রণ করতে পারে 10 bহিসাবে চিহ্নিত করা volatileনিশ্চিত করে যে এটি পুনরায় অর্ডার হবে না (বা নির্দিষ্ট কিছু ক্ষেত্রে ফেলে দেওয়া হবে)। যার অর্থ থ্রেডবি কেবল 20 টি মুদ্রণ করতে পারে (বা কিছুই নয়)। পদ্ধতিগুলি সিঙ্ক্রোনাইজড হিসাবে চিহ্নিত করা একই ফলাফল অর্জন করবে। হিসাবে একটি ভেরিয়েবল চিহ্নিতvolatile এটি নিশ্চিত করে যে এটি পুনরায় অর্ডার হবে না, তবে এর আগে / পরে সবকিছু পুনঃক্রম হতে পারে, সুতরাং কিছু পরিস্থিতিতে দৃশ্যের সাথে সিঙ্ক্রোনাইজেশন আরও উপযুক্ত হতে পারে।

নোট করুন যে জাভা 5 নতুন মেমোরি মডেলের আগে, উদ্বায়ী এই সমস্যাটি সমাধান করেনি।


1
"এটি কোনও অপারেশনের মতো দেখতে হলেও এটি আসলে 3: মেমরি থেকে এক্সের বর্তমান মান পড়া, এটিতে 1 যুক্ত করা এবং এটিকে মেমোরিতে ফিরিয়ে দেওয়া"। - ঠিক আছে, কারণ মেমরি থেকে মানগুলি অবশ্যই যুক্ত / পরিবর্তন করার জন্য সিপিইউ সার্কিট্রির মধ্য দিয়ে যেতে হবে। যদিও এটি কেবল একটি একক সমাবেশের INCঅপারেশনে রূপান্তরিত হয়, অন্তর্নিহিত সিপিইউ অপারেশনগুলি এখনও 3 গুণ এবং থ্রেড সুরক্ষার জন্য লকিংয়ের প্রয়োজন। ভাল যুক্তি. যদিও, INC/DECকমান্ডগুলি পারমাণবিকভাবে সমাবেশে পতাকাঙ্কিত হতে পারে এবং এখনও 1 টি পরমাণু অপারেশন হতে পারে।
Zombies

@ জম্বিগুলি তাই যখন আমি এক্স ++ এর জন্য একটি সিঙ্ক্রোনাইজড ব্লক তৈরি করি, তখন কী এটি এটিকে পতাকাঙ্কিত পারমাণবিক আইএনসি / ডিসি রূপান্তরিত করে বা এটি কোনও নিয়মিত লক ব্যবহার করে?
ডেভিড রেফায়েলি

আমি জানি না! আমি যা জানি তা হ'ল আইএনসি / ডিসি পারমাণবিক নয় কারণ কোনও সিপিইউর জন্য এটির মূল্য লোড করতে হবে এবং এটি পড়তে হবে এবং এটি (স্মৃতিতে) লিখতে হবে, ঠিক যেমন অন্যান্য পাটিগণিত ক্রিয়াকলাপের মতো।
জম্বি 19
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.