Java.util.HashMap থেকে একাধিক থ্রেড (কোনও পরিবর্তন নেই) থেকে মান পাওয়া নিরাপদ?


138

এমন একটি মামলা রয়েছে যেখানে মানচিত্র তৈরি করা হবে এবং এটি একবার শুরু করার পরে এটি আর কখনও সংশোধিত হবে না। তবে এটি একাধিক থ্রেড থেকে (কেবল get (কী) এর মাধ্যমে) অ্যাক্সেস করা হবে। java.util.HashMapএভাবে ব্যবহার করা কি নিরাপদ ?

(বর্তমানে, আমি আনন্দের সাথে একটি ব্যবহার করছি java.util.concurrent.ConcurrentHashMap, এবং পারফরম্যান্সের উন্নতি করতে কোন মাপা প্রয়োজন আছে, কিন্তু কেবল জানতে আগ্রহী একটি সহজ am HashMapযথেষ্ট হবে। তাই, এই প্রশ্ন হল না "এক ব্যবহার করবো?" না এটা একটি কার্যকারিতা প্রশ্ন। বরং প্রশ্নটি "এটি কি নিরাপদ হবে?")


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

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

এটা স্ট্যাটিক্যালি সক্রিয়া এর এবং স্ট্যাটিক ব্লক বাইরে সংশোধন না ফেলেন, তাহলে এটি ঠিক হতে পারে কারণ সব স্ট্যাটিক আরম্ভের দ্বারা সিঙ্ক্রোনাইজ করা আছে ClassLoader। এটি নিজস্ব একটি পৃথক প্রশ্ন মূল্যবান। আমি এখনও স্পষ্টভাবে এটি এবং প্রোফাইলটিকে সিঙ্ক্রোনাইজ করব যাচাই করতে এটি বাস্তব পারফরম্যান্স সমস্যার কারণ হয়ে দাঁড়িয়েছে।
সীমানা

@ হিথবর্ডারস - "মেমরি আপডেট" বলতে কী বোঝ? জেভিএম একটি আনুষ্ঠানিক মডেল যা দৃশ্যমানতা, পারমাণবিকতা, সম্পর্কের আগে ঘটে যাওয়া সম্পর্কিত বিষয়গুলি সংজ্ঞায়িত করে তবে "মেমরি আপডেট" এর মতো পদ ব্যবহার করে না। আপনার স্পষ্ট করা উচিত, জেএলএস থেকে সংজ্ঞাটি ব্যবহার করা উচিত।
BeeOnRope

2
@ ডেভ - আমি ধরে নিয়েছি আপনি 8 বছর পরেও উত্তর খুঁজছেন না, তবে রেকর্ডটির জন্য, প্রায় সমস্ত উত্তরের মূল বিভ্রান্তি হ'ল তারা মানচিত্রের অবজেক্টে আপনার করা পদক্ষেপগুলিতে ফোকাস করে । আপনি ইতিমধ্যে ব্যাখ্যা করেছেন যে আপনি কখনই বস্তুটি সংশোধন করেন না, এটি সমস্ত অপ্রাসঙ্গিক। কেবলমাত্র সম্ভাব্য "গ্যাচা" হ'ল আপনি কীভাবে সেই প্রবন্ধটি প্রকাশ করবেন Map, যা আপনি ব্যাখ্যা করেন নি। আপনি যদি এটি নিরাপদে না করেন তবে এটি নিরাপদ নয়। আপনি যদি এটি নিরাপদে করেন তবে তা হয় । আমার উত্তরে বিশদ।
BeeOnRope

উত্তর:


55

তোমার বাগ্ধারা নিরাপদ যদি এবং কেবল যদি রেফারেন্স 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] :

  1. সঠিকভাবে লক করা ক্ষেত্রের মাধ্যমে রেফারেন্সটি বিনিময় করুন ( জেএলএস 17.4.5 )
  2. প্রারম্ভিক স্টোরগুলি করতে স্ট্যাটিক ইনিশিয়ালাইজার ব্যবহার করুন ( জেএলএস 12.4 )
  3. একটি অস্থির ক্ষেত্র ( JLS 17.4.5 ) এর মাধ্যমে রেফারেন্সটি বিনিময় করুন বা অ্যাটমিকএক্স ক্লাসের মাধ্যমে এই নিয়মের ফলাফল হিসাবে
  4. একটি চূড়ান্ত ক্ষেত্রের ( 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পড়ুন - কিন্তু এই আজ খুব বিরল।


never modify HashMapমানে এই নয় state of the map objectআমি মনে করি থ্রেড নিরাপদ। Theশ্বর গ্রন্থাগারের বাস্তবায়ন জানেন, যদি সরকারী দস্তাবেজ না বলে এটি থ্রেড নিরাপদ।
জিয়াং ওয়াইডি

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

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

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

সুতরাং HashMapযে পদ্ধতিগুলির জন্য আমরা কেবলমাত্র পঠনযোগ্য হওয়ার প্রত্যাশা করি কেবল সেগুলি কেবল পঠনযোগ্য, কারণ তারা কাঠামোগতভাবে সংশোধন করে না HashMap। অবশ্যই, এই গ্যারান্টিটি নির্বিচারে অন্যান্য Mapপ্রয়োগের জন্য রাখা নাও পারে , তবে প্রশ্নটি HashMapবিশেষভাবে।
BeeOnRope

70

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

এই বিষয়ে আরও তথ্যের জন্য, জেরেমির ব্লগ পোস্টগুলি পড়ুন:

জাভাতে অপ্রয়োজনীয়তার প্রথম ভাগ: http://jeremymanson.blogspot.com/2008/04/immutability-in-java.html

জাভাতে অপ্রয়োজনীয়তার উপর পার্ট 2: http://jeremymanson.blogspot.com/2008/07/immutability-in-java-part-2.html

জাভাতে অপ্রয়োজনীয়তার উপর পার্ট 3: http://jeremymanson.blogspot.com/2008/07/immutability-in-java-part-3.html


3
এটি একটি ভাল বিষয়, তবে আমি স্থির সূচনার উপর নির্ভর করছি, যার সময় কোনও রেফারেন্স এড়ায় না, তাই এটি নিরাপদ হওয়া উচিত।
ডেভ এল।

5
আমি দেখতে ব্যর্থ হলাম কীভাবে এটি একটি উচ্চ রেটযুক্ত উত্তর (বা এমনকি একটি উত্তর)। এটি, একটির জন্য, এমনকি প্রশ্নের উত্তর দেয় না এবং এটি একটি মূল নীতি উল্লেখ করে না যা এটি নিরাপদ কিনা তা স্থির করবে: নিরাপদ প্রকাশনা । "উত্তর "টি" এটি কৌতুকপূর্ণ "হয়ে যায় এবং এখানে আপনি পড়তে পারেন এমন তিনটি (জটিল) লিঙ্ক রয়েছে।
BeeOnRope

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

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

35

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

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

দেখুন নতুন জাভা মেমরি মডেল উপর ব্রায়ান Goetz এর নিবন্ধ বিস্তারিত জানার জন্য।


দ্বৈত জমা দেওয়ার জন্য দুঃখিত, আমি আমার জমা দেওয়ার পরে কেবলমাত্র আপনার লক্ষ্য করেছি। :)
আলেকজান্ডার

2
আমি কেবল এখানে খুশিই আছি যে এখানে অন্যান্য লোকেরা আসলে স্মৃতি-প্রভাবগুলি বুঝতে পারে।
সীমানা

1
আসলে, যদিও কোনও থ্রেড সঠিকভাবে আরম্ভ করার আগে অবজেক্টটি দেখতে পাবে না, তাই আমি মনে করি না যে এটি এই ক্ষেত্রে উদ্বেগজনক।
ডেভ এল।

1
এটি পুরোপুরি নির্ভর করে যে কীভাবে অবজেক্টটি আরম্ভ করা হয়।
বিল মিশেল

1
প্রশ্নটি বলছে যে একবার হ্যাশম্যাপ শুরু হয়ে গেলে সে আর কোনও আপডেট করার ইচ্ছা করে না। তারপরে, তিনি কেবল এটি পঠনযোগ্য ডেটা স্ট্রাকচার হিসাবে ব্যবহার করতে চান। আমি মনে করি, এটি করা নিরাপদ হবে, প্রদত্ত, তার মানচিত্রে সঞ্চিত ডেটা পরিবর্তনযোগ্য।
বিনিতা ভারতী

9

আরও কিছুক্ষন দেখার পরে, আমি এটি জাভা ডকটিতে পেয়েছি (জোর দেওয়া আমার):

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

এ থেকে বোঝা যাচ্ছে যে এটি নিরাপদে থাকবে, ধরে নিলে সেখানে থাকা বক্তব্যটির কথোপকথনটি সত্য।


1
যদিও এটি উত্তম পরামর্শ, অন্য উত্তরগুলির হিসাবে উল্লেখ করা যায়, অপরিবর্তনীয়, নিরাপদে প্রকাশিত মানচিত্রের ক্ষেত্রে আরও একটি উত্তরসূচক উত্তর রয়েছে। আপনি যা করছেন তা যদি আপনি জানেন তবেই আপনার এটি করা উচিত।
অ্যালেক্স মিলার

1
আশা করি আমাদের মতো আরও কয়েকটি প্রশ্নের সাথে আমরা কী করছি তা জানতে পারবেন।
ডেভ এল।

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

9

একটি দ্রষ্টব্য হ'ল কিছু পরিস্থিতিতে, একটি অচ্ছলঙ্কিত হ্যাশম্যাপ থেকে প্রাপ্ত () একটি অসীম লুপ তৈরি করতে পারে। যদি কোনও সমবর্তী পুট () মানচিত্রের পুনঃস্থাপনের কারণ হয়ে থাকে তবে এটি ঘটতে পারে।

http://lightbody.net/blog/2005/07/hashmapget_can_cause_an_infini.html


1
আসলে আমি এই সিপিইউ না খেয়ে জেভিএমকে ঝুলিয়ে থাকতে দেখেছি (যা সম্ভবত আরও খারাপ)
পিটার লরে

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

@ অ্যালেক্সমিলার এমনকি অন্য কারণগুলি থেকে আলাদা করে (আমি ধরে নিই যে আপনি নিরাপদ প্রকাশের কথা উল্লেখ করছেন), আমি মনে করি না যে বাস্তবায়নের পরিবর্তনটি ডকুমেন্টের দ্বারা স্পষ্টভাবে অনুমোদিত না হয়ে থাকলে অ্যাক্সেস সীমাবদ্ধতাগুলি হ্রাস করার কারণ হতে হবে be যেমনটি ঘটে, জাভা 8 এর জন্য হ্যাশম্যাপNote that this implementation is not synchronized. If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally.
জাভাদোকটিতে

8

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


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

@ অ্যালেক্স: হ্যাশম্যাপের উল্লেখটি একই মেমরির দৃশ্যমানতার গ্যারান্টি তৈরি করতে উদ্বায়ী হতে পারে। @Dave: এটা হল নতুন objs উল্লেখ দেখতে আগে তার ctor কাজ আপনার থ্রেডে দৃশ্যমান হয় সম্ভব।
ক্রিস ভেস্ট

@ খ্রিস্টিয়ান সাধারণ ক্ষেত্রে অবশ্যই। আমি বলছিলাম যে এই কোডে, এটি না।
ডেভ এল।

একটি র‌্যান্ডম লক অর্জন করা পুরো থ্রেড সিপিইউ ক্যাশে সাফ হওয়ার গ্যারান্টি দেয় না। এটি জেভিএম বাস্তবায়নের উপর নির্ভর করে এবং সম্ভবত এটি এভাবে করা হয়নি।
পিয়েরে

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

5

Http://www.ibm.com/developerworks/java/library/j-jtp03304/ এর মতে # সুরক্ষা সুরক্ষা আপনি আপনার হ্যাশম্যাপকে একটি চূড়ান্ত ক্ষেত্র করতে পারেন এবং নির্মাতা শেষ হওয়ার পরে এটি নিরাপদে প্রকাশিত হবে।

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


এই উত্তরটি নিম্নমানের, এটি @ টেলর গৌথিয়ারের উত্তর হিসাবে একই তবে কম বিশদ সহ।
Snicolas

1
উম্ম্ম্ম ... গাধা হতে হবে না, তবে তোমার পেছনের দিকে আছে। টেলর বলেছিলেন, "না, এই ব্লগ পোস্টটি দেখুন, উত্তরটি আপনাকে চমকে দিতে পারে", যদিও এই উত্তরটি আসলে এমন একটি নতুন যুক্ত করেছে যা আমি জানতাম না ... একটি ক্ষেত্রে একটি চূড়ান্ত ক্ষেত্র লেখার আগে ঘটে যাওয়া সম্পর্কের সম্পর্কে কন্সট্রাকটর। এই উত্তরটি দুর্দান্ত, এবং আমি এটি পড়ে আনন্দিত।
আজাক্স

তাই না? উচ্চতর রেটযুক্ত উত্তরের মাধ্যমে স্ক্রোল করার পরে এটিই কেবলমাত্র সঠিক উত্তর। কীটি নিরাপদে প্রকাশিত হয়েছে এবং এটিই একমাত্র উত্তর যা এমনকি এটির উল্লেখ করেছে।
BeeOnRope

3

সুতরাং আপনি যে দৃশ্যের বর্ণনা দিয়েছিলেন তা হ'ল আপনাকে মানচিত্রে একগুচ্ছ ডেটা রাখা দরকার, এরপরে আপনি যখন এটি জনসাধারণের কাজ শেষ করেন তখন আপনি এটিকে অপরিবর্তনীয় বলে মনে করেন। "নিরাপদ" (যার অর্থ আপনি প্রয়োগ করছেন যে এটি সত্যিকারের অপরিবর্তনীয় বলে বিবেচনা করা হয়) এর একটি পদ্ধতির হ'ল রেফারেন্সটি Collections.unmodifiableMap(originalMap)যখন আপনি স্থাবর করতে প্রস্তুত তখন তা প্রতিস্থাপন করা ।

যদি একই সাথে ব্যবহার করা হয় তবে মানচিত্রগুলি কীভাবে খারাপভাবে ব্যর্থ হতে পারে এবং উদাহরণস্বরূপ যে কাজের প্রস্তাবটি আমি উল্লেখ করেছি, উদাহরণস্বরূপ, এই বাগের প্যারেড এন্ট্রিটি দেখুন: বাগ_আইডি = 6423457


2
এটি "নিরাপদ" যাতে এটি অপরিবর্তনীয়তা প্রয়োগ করে, তবে এটি থ্রেড সুরক্ষা ইস্যুটির সমাধান করে না। যদি মানচিত্রটি UnmodifiableMap মোড়কের সাথে অ্যাক্সেস করতে নিরাপদ থাকে তবে এটি ছাড়া এটি নিরাপদ এবং তদ্বিপরীত।
ডেভ এল।

2

এই প্রশ্নটির সমাধান ব্রায়ান গয়েটসের "অনুশীলনে জাভা কনকুরન્સી" বইয়ে রয়েছে (তালিকাভুক্ত 16.8, পৃষ্ঠা 350):

@ThreadSafe
public class SafeStates {
    private final Map<String, String> states;

    public SafeStates() {
        states = new HashMap<String, String>();
        states.put("alaska", "AK");
        states.put("alabama", "AL");
        ...
        states.put("wyoming", "WY");
    }

    public String getAbbreviation(String s) {
        return states.get(s);
    }
}

যেহেতু statesঘোষিত হয়েছে finalএবং এর প্রাথমিককরণটি মালিকের শ্রেণি নির্মাতার মধ্যে সম্পন্ন হয়েছে, যে কোনও থ্রেড পরে এই মানচিত্রটি পড়ে এটি নির্ধারক শেষ হওয়ার সময় হিসাবে এটি দেখার নিশ্চয়তা দেওয়া হয়, অন্য কোনও থ্রেড মানচিত্রের বিষয়বস্তুগুলিকে সংশোধন করার চেষ্টা করবে না।


1

সতর্কতা অবলম্বন করুন যে একক-থ্রেডযুক্ত কোডেও একটি কনক্র্যান্ট হ্যাশম্যাপকে হ্যাশম্যাপের সাথে প্রতিস্থাপন করা নিরাপদ নাও হতে পারে। সমবর্তী হ্যাশম্যাপটি কোনও কী বা মান হিসাবে নালকে নিষেধ করে। হ্যাশম্যাপ তাদের নিষেধ করে না (জিজ্ঞাসা করবেন না)।

সুতরাং আপনার বিদ্যমান কোডটি সেটআপের সময় সংগ্রহটি বাতিল করতে পারে (সম্ভাব্যত কোনওরকম ব্যর্থতার ক্ষেত্রে সম্ভবত) সংকলনটিকে বর্ণিত হিসাবে প্রতিস্থাপন করলে কার্যকরী আচরণে পরিবর্তন আসবে the

এটি বলেছিল, যদি আপনি কোনও হ্যাশম্যাপ থেকে সামঞ্জস্যপূর্ণ আর কিছু না করেন তবে নিরাপদ।

[সম্পাদনা করুন: "সমবর্তী পাঠগুলি" দ্বারা, আমি বোঝাতে চাইছি সেখানে একই সাথে সামঞ্জস্য পরিবর্তনও হয় নি।

অন্যান্য উত্তরগুলি এটি কীভাবে নিশ্চিত করা যায় তা ব্যাখ্যা করে। একটি উপায় হ'ল মানচিত্রটিকে অপরিবর্তনীয় করে তোলা, তবে এটি প্রয়োজনীয় নয়। উদাহরণস্বরূপ, জেএসআর 133 মেমরি মডেল স্পষ্টভাবে সংশ্লেষিত ক্রিয়া হিসাবে থ্রেড শুরু করার সংজ্ঞা দেয়, যার অর্থ থ্রেড বি শুরু হওয়ার আগে থ্রেড এ-তে হওয়া পরিবর্তনগুলি থ্রেড বিতে দৃশ্যমান হয় B.

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


সতর্কতার জন্য ধন্যবাদ, তবে নাল কী বা মানগুলি ব্যবহার করার চেষ্টা করা হয়নি।
ডেভ এল।

ভেবেছিলাম ওখানে হবে না। সংগ্রহের নালগুলি জাভাটির এক উন্মাদ কোণ।
স্টিভ জেসোপ

আমি এই উত্তরের সাথে একমত নই "একটি হ্যাশম্যাপ থেকে সমকালীন পাঠগুলি নিরাপদ" নিজে থেকে ভুল। এটি লিখিত হয় না যে পাঠাগুলি এমন মানচিত্রের বিরুদ্ধে ঘটছে যা পরিবর্তনীয় বা পরিবর্তনযোগ্য। সঠিক হতে হলে এটি পড়তে হবে "একটি পরিবর্তনীয় হ্যাশম্যাপ থেকে সমকালীন পাঠগুলি নিরাপদ"
টেলর গৌটিয়ার

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

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

0

http://www.docjar.com/html/api/java/util/HashMap.java.html

এখানে হ্যাশম্যাপের উত্স। যেমন আপনি বলতে পারেন, সেখানে কোনও লকিং / মিটেক্স কোড নেই।

এর অর্থ হ'ল একটি বহুবিবাহিত পরিস্থিতিতে একটি হ্যাশম্যাপ থেকে পড়া ঠিক আছে, আমি একাধিক লেখক থাকলে অবশ্যই একটি কনকন্টারহ্যাশম্যাপটি ব্যবহার করব।

মজার বিষয় হ'ল। নেট হ্যাশটবেল এবং অভিধান <কে, ভি> উভয়ই সিঙ্ক্রোনাইজেশন কোড তৈরি করেছে।


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

0

যদি সূচনা এবং প্রতিটি পুট সিঙ্ক্রোনাইজ হয় তবে আপনি সংরক্ষণ করবেন।

নিম্নোক্ত কোডটি সংরক্ষণ করা হয়েছে কারণ শ্রেণিবদ্ধকারী সিঙ্ক্রোনাইজেশনের যত্ন নেবে:

public static final HashMap<String, String> map = new HashMap<>();
static {
  map.put("A","A");

}

নিম্নলিখিত কোডটি সংরক্ষণ করা হয় কারণ অস্থির লেখাগুলি সিঙ্ক্রোনাইজেশনের যত্ন নেবে।

class Foo {
  volatile HashMap<String, String> map;
  public void init() {
    final HashMap<String, String> tmp = new HashMap<>();
    tmp.put("A","A");
    // writing to volatile has to be after the modification of the map
    this.map = tmp;
  }
}

সদস্য ভেরিয়েবল চূড়ান্ত হলে এটিও কাজ করবে কারণ চূড়ান্তটিও অস্থির। এবং পদ্ধতিটি যদি কোনও কনস্ট্রাক্টর হয়।

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