তোমার বাগ্ধারা নিরাপদ যদি এবং কেবল যদি রেফারেন্স HashMapহয় নিরাপদে প্রকাশিত । HashMapনিজের অভ্যন্তরের সাথে সম্পর্কিত কোনও কিছুর চেয়ে নিরাপদ প্রকাশনাটি কীভাবে নির্মাণের থ্রেডটিকে অন্য থ্রেডে মানচিত্রের রেফারেন্সটি দৃশ্যমান করে তোলে তা নিয়ে কাজ করে।
মূলত, এখানে কেবলমাত্র সম্ভাব্য রেসটি HashMapসম্পূর্ণরূপে নির্মাণের আগেই এটি অ্যাক্সেস করতে পারে এমন কোনও পড়ার থ্রেড নির্মাণের মধ্যে রয়েছে। বেশিরভাগ আলোচনার বিষয়টি ম্যাপের অবজেক্টের অবস্থার কী হয় তা নিয়ে, তবে এটি অপ্রাসঙ্গিক যেহেতু আপনি কখনই এটি পরিবর্তন করেন না - তাই কেবল আকর্ষণীয় অংশটি কীভাবে HashMapরেফারেন্স প্রকাশিত হয়।
উদাহরণস্বরূপ, কল্পনা করুন আপনি এইভাবে মানচিত্র প্রকাশ করেছেন:
class SomeClass {
public static HashMap<Object, Object> MAP;
public synchronized static setMap(HashMap<Object, Object> m) {
MAP = m;
}
}
... এবং এক পর্যায়ে setMap()কোনও মানচিত্রের সাথে ডাকা হয় এবং অন্যান্য থ্রেডগুলি SomeClass.MAPমানচিত্রটি অ্যাক্সেস করতে ব্যবহার করে এবং নালটির জন্য এটি পরীক্ষা করে থাকে:
HashMap<Object,Object> map = SomeClass.MAP;
if (map != null) {
.. use the map
} else {
.. some default behavior
}
এই নিরাপদ নয় যদিও এটি সম্ভবত মনে হচ্ছে, যেন এটা। সমস্যাটি হ'ল এর আগেSomeObject.MAP আর কোনও থ্রেডের সেট এবং পরবর্তী পাঠের মধ্যে সম্পর্ক হওয়ার আগে কোনও ঘটনা ঘটে না , তাই পঠন থ্রেডটি আংশিকভাবে নির্মিত মানচিত্রটি মুক্ত free এটি বেশ কিছু করতে পারে এবং অনুশীলনে এটি পাঠ্য থ্রেডকে অসীম লুপে রাখার মতো কাজ করে ।
নিরাপদে মানচিত্র প্রকাশ করতে, আপনাকে প্রতিষ্ঠা করতে প্রয়োজন ঘটবে-পূর্বে মধ্যে সম্পর্ক রেফারেন্স লেখা থেকে HashMap(অর্থাত, প্রকাশন ) এবং যে রেফারেন্স (অর্থাত, খরচ) পরবর্তী পাঠকদের। সুবিধামত, আছে মাত্র কয়েক সহজ মনে রাখার যোগ্য করার উপায় সাধা যে [1] :
- সঠিকভাবে লক করা ক্ষেত্রের মাধ্যমে রেফারেন্সটি বিনিময় করুন ( জেএলএস 17.4.5 )
- প্রারম্ভিক স্টোরগুলি করতে স্ট্যাটিক ইনিশিয়ালাইজার ব্যবহার করুন ( জেএলএস 12.4 )
- একটি অস্থির ক্ষেত্র ( JLS 17.4.5 ) এর মাধ্যমে রেফারেন্সটি বিনিময় করুন বা অ্যাটমিকএক্স ক্লাসের মাধ্যমে এই নিয়মের ফলাফল হিসাবে
- একটি চূড়ান্ত ক্ষেত্রের ( JLS 17.5 ) মান শুরু করুন ।
আপনার দৃশ্যের জন্য সবচেয়ে আকর্ষণীয় বিষয়গুলি হ'ল (2), (3) এবং (4)। বিশেষত, (3) আমার উপরের কোডটিতে সরাসরি প্রযোজ্য: আপনি যদি এই ঘোষণাকে রূপান্তর করেন MAP:
public static volatile HashMap<Object, Object> MAP;
তারপরে সব কিছুই কোশার: পাঠকদের যারা অ-নাল মান দেখে অগত্যা স্টোরের সাথে তার আগে সম্পর্ক হয় MAPএবং তাই মানচিত্রের আরম্ভের সাথে যুক্ত সমস্ত স্টোর দেখতে পান।
অন্যান্য পদ্ধতিগুলি আপনার পদ্ধতির শব্দার্থকে পরিবর্তন করে, যেহেতু (2) (স্ট্যাটিক ইনিটালাইজার ব্যবহার করে) এবং (4) ( চূড়ান্ত ব্যবহার) উভয়ই বোঝায় যে আপনি MAPরানটাইমটিতে গতিশীলভাবে সেট করতে পারবেন না । যদি আপনার এটি করার প্রয়োজন না হয় তবে কেবল MAPএকটি হিসাবে ঘোষণা করুন static final HashMap<>এবং আপনাকে নিরাপদ প্রকাশের নিশ্চয়তা দেওয়া হচ্ছে।
অনুশীলনে, "কখনই সংশোধিত বস্তুগুলিতে" নিরাপদ অ্যাক্সেসের জন্য নিয়মগুলি সহজ:
আপনি যদি এমন কোনও বিষয় প্রকাশ করছেন যা সহজাতভাবে স্থাবর নয় (যেমন ঘোষণা করা সমস্ত ক্ষেত্রে রয়েছে final) এবং:
- আপনি ঘোষণার মুহুর্তে নির্ধারিত অবজেক্টটি ইতিমধ্যে তৈরি করতে পারেন a : কেবলমাত্র একটি
finalক্ষেত্র ( static finalস্থির সদস্যদের সহ ) ব্যবহার করুন।
- রেফারেন্সটি ইতিমধ্যে দৃশ্যমান হওয়ার পরে আপনি পরে বিষয়টি নির্ধারণ করতে চান: একটি উদ্বায়ী ক্ষেত্র ব্যবহার করুন খ ।
এটাই!
অনুশীলনে, এটি খুব দক্ষ। static finalউদাহরণস্বরূপ, কোনও ক্ষেত্রের ব্যবহার জেভিএমকে প্রোগ্রামের জীবনের জন্য অপরিবর্তিত মূল্য ধরে নিতে এবং এটি ভারীভাবে অনুকূলিত করতে দেয়। finalসদস্য ক্ষেত্রের ব্যবহার বেশিরভাগ আর্কিটেকচারকে ক্ষেত্রটি সাধারণ ক্ষেত্রের সমানভাবে পড়তে দেয় এবং আরও অনুকূলিতকরণ বাধা দেয় না c ।
শেষ অবধি, এর ব্যবহারের volatileকিছু প্রভাব রয়েছে: অনেকগুলি আর্কিটেকচারে কোনও হার্ডওয়্যার বাধা প্রয়োজন নেই (যেমন x86, বিশেষত যা পাঠকদের পাঠ্য পাস করার অনুমতি দেয় না), তবে কিছু অপ্টিমাইজেশন এবং পুনর্নির্মাণ সংকলনের সময় নাও হতে পারে - তবে এটি প্রভাব সাধারণত ছোট। বিনিময়ে, আপনি যা চেয়েছিলেন তার চেয়ে বেশি আপনি পাবেন - কেবল আপনি নিরাপদে একটি প্রকাশ করতে HashMapপারবেন না, আপনি HashMapএকই রেফারেন্সের জন্য চান আরও অনেকগুলি সংশোধিত গুলি সংরক্ষণ করতে পারবেন এবং আশ্বাস দিন যে সমস্ত পাঠক নিরাপদে প্রকাশিত মানচিত্রটি দেখতে পাবেন ।
আরও উদ্ভট বিবরণের জন্য শিপিলিভ বা ম্যানসন এবং গয়েটসের এই FAQ দেখুন ।
[1] শিপিলিভ থেকে সরাসরি উদ্ধৃতি ।
একটি যে শব্দসমূহ জটিল, কিন্তু কি আমি বলতে চাচ্ছি যে আপনি নির্মাণ সময়ে রেফারেন্স ধার্য করতে পারেন হয় - হয় ঘোষণা সময়ে বা কন্সট্রাক্টর (সদস্য ক্ষেত্র) অথবা স্ট্যাটিক সূচনাকারী (স্ট্যাটিক ক্ষেত্রগুলিতে) হবে।
খ allyচ্ছিকভাবে, আপনি একটি synchronizedসেট / সেট করতে একটি পদ্ধতি ব্যবহার করতে পারেন , বা একটি AtomicReferenceবা অন্য কিছু, তবে আমরা আপনি করতে পারেন ন্যূনতম কাজ সম্পর্কে বলছি।
গ খুব দুর্বল স্মৃতি মডেল (আমি দিকে তাকিয়ে আছি কিছু আর্কিটেকচারের আপনি , আলফা) একটি সামনে পঠিত বাধা কিছু টাইপ করার প্রয়োজন হতে পারে finalপড়ুন - কিন্তু এই আজ খুব বিরল।