জাভা সিঙ্ক্রোনাইজড ব্লক বনাম কালেকশনস.সিঙ্ক্রোনাইজড ম্যাপ


85

নীচের কোডগুলি কলগুলি সঠিকভাবে সিঙ্ক্রোনাইজ করার জন্য সেট আপ করা আছে synchronizedMap?

public class MyClass {
  private static Map<String, List<String>> synchronizedMap = Collections.synchronizedMap(new HashMap<String, List<String>>());

  public void doWork(String key) {
    List<String> values = null;
    while ((values = synchronizedMap.remove(key)) != null) {
      //do something with values
    }
  }

  public static void addToMap(String key, String value) {
    synchronized (synchronizedMap) {
      if (synchronizedMap.containsKey(key)) {
        synchronizedMap.get(key).add(value);
      }
      else {
        List<String> valuesList = new ArrayList<String>();
        valuesList.add(value);
        synchronizedMap.put(key, valuesList);
      }
    }
  }
}

আমার বোঝাপড়া থেকে, addToMap()অন্য থ্রেডটি কল করতে remove()বা আটকাতে বাধা containsKey()দেওয়ার আগে আমার put()একটি সিঙ্ক্রোনাইজড ব্লক দরকার তবে আমার কোনও সিঙ্ক্রোনাইজড ব্লকের দরকার নেই doWork()কারণ অন্য থ্রেড রিটার্নের addToMap()আগে সিঙ্ক্রোনাইজড ব্লকে প্রবেশ করতে পারে না remove()কারণ আমি মূলত মানচিত্রটি তৈরি করেছি সঙ্গে Collections.synchronizedMap()। এটা কি ঠিক? এই কাজ করতে একটি ভাল উপায় আছে কি?

উত্তর:


90

Collections.synchronizedMap() গ্যারান্টি দেয় যে মানচিত্রে আপনি চালাতে চান প্রতিটি পারমাণবিক ক্রিয়াকলাপ সিঙ্ক্রোনাইজ হবে।

মানচিত্রে দুটি (বা আরও) ক্রিয়াকলাপ চালানো অবশ্যই একটি ব্লকে সিঙ্ক্রোনাইজ করতে হবে। সুতরাং হ্যাঁ - আপনি সঠিকভাবে সিঙ্ক্রোনাইজ করছেন।


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

4
@ ইউভাল আপনি নিজের উত্তরটি আরও কিছুটা গভীরভাবে ব্যাখ্যা করতে পারবেন? আপনি বলছেন সিঙ্ক্রোনাইজড ম্যাপ অ্যাটমিকভাবে অপারেশন করে তবে সিঙ্কম্যাপ আপনার সমস্ত ক্রিয়াকলাপকে পারমাণবিক করে তোলে তবে কেন আপনার নিজের সিঙ্ক্রোনাইজড ব্লকের প্রয়োজন হবে? আপনার প্রথম অনুচ্ছেদে দ্বিতীয়টি নিয়ে উদ্বেগ প্রকাশ করা উচিত বলে মনে হচ্ছে।
almel

@ আলমেল আমার উত্তর দেখুন
সের্গেই

4
ইতিমধ্যে মানচিত্রটি যেমন ব্যবহার করছে তেমনি কেন সিঙ্ক্রোনাইজ হওয়া প্রয়োজন Collections.synchronizedMap()? আমি দ্বিতীয় পয়েন্ট পাচ্ছি না।
বিমল শর্মা


13

নেই সম্ভাব্য আপনার কোডে একটি সূক্ষ্ম বাগ জন্য।

[ আপডেট: যেহেতু তিনি মানচিত্রটি ব্যবহার করছেন remটি সরান () এই বিবরণটি সম্পূর্ণ বৈধ নয়। আমি এই ঘটনাটি প্রথমবারের মতো মিস করেছি। :( যে। আমি বাকি চলে যাচ্ছি হয়, কিন্তু নেতৃত্ব বিবৃতি বলতে নেই পরিবর্তিত ইশারা জন্য প্রশ্ন লেখক ধন্যবাদ সম্ভাব্য একটি বাগ।]

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

আপনি মানচিত্রের মতো একটি সিঙ্ক্রোনাইজড তালিকা byুকিয়ে এটি ঠিক করতে পারেন

List<String> valuesList = new ArrayList<String>();
valuesList.add(value);
synchronizedMap.put(key, Collections.synchronizedList(valuesList)); // sync'd list

বিকল্পভাবে আপনি ডো ওয়ার্কের লিস্টে অ্যাক্সেস করার সময় মানচিত্রে সিঙ্ক্রোনাইজ করতে পারবেন () :

  public void doWork(String key) {
    List<String> values = null;
    while ((values = synchronizedMap.remove(key)) != null) {
      synchronized (synchronizedMap) {
          //do something with values
      }
    }
  }

শেষ বিকল্পটি সামঞ্জস্যকে কিছুটা সীমাবদ্ধ করবে, তবে এটি কিছুটা পরিষ্কার আইএমও।

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

এই শ্রেণিটি হ্যাশটেবলের সাথে এমন প্রোগ্রামগুলিতে সম্পূর্ণরূপে আন্তঃযোগাযোগ্য যেগুলি এর থ্রেড সুরক্ষার উপর নির্ভর করে তবে এটির সিঙ্ক্রোনাইজেশন বিশদ নয়

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

শেষ জিনিস. :) অনুশীলনে জাভা কনকুরেন্সির এই দুর্দান্ত উক্তিটি সর্বদা আমাকে একটি ডিবাগিং মাল্টি-থ্রেড প্রোগ্রাম ডিজাইনে সহায়তা করে।

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


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

সঠিক! আমি আপনার অপসারণ পুরোপুরি হাওয়া।
জেএলআর

4
একাধিক থ্রেড দ্বারা অ্যাক্সেস করা যায় এমন প্রতিটি পরিবর্তনীয় রাষ্ট্রের পরিবর্তনশীলগুলির জন্য, সেই ভেরিয়েবলের সমস্ত অ্যাক্সেস অবশ্যই একই লক ধারণ করে সম্পাদন করা উচিত। ---- আমি সাধারণত একটি ব্যক্তিগত সম্পত্তি যুক্ত করি যা কেবলমাত্র একটি নতুন অবজেক্ট () এবং এটি আমার সিঙ্কোনাইজেশন ব্লকের জন্য ব্যবহার করে। এই প্রসঙ্গে আমি এই সমস্তটি কাঁচা মাধ্যমে জানি। সিঙ্ক্রোনাইজড (অবজেক্টআইএনভার) {}
অ্যান্থনি জে ক্লিঙ্ক

11

হ্যাঁ, আপনি সঠিকভাবে সিঙ্ক্রোনাইজ করছেন। আমি আরও বিস্তারিতভাবে এটি ব্যাখ্যা করব। আপনাকে সিঙ্ক্রোনাইজড ম্যাপ অবজেক্টে কেবল দুটি বা ততোধিক পদ্ধতি কল সিঙ্ক্রোনাইজ করা আবশ্যক কেবলমাত্র সিঙ্ক্রোনাইজড ম্যাপ অবজেক্টে পদ্ধতি কলগুলির ক্রম অনুসারে পরবর্তী পদ্ধতি কলটিতে পূর্ববর্তী পদ্ধতি কল (গুলি) এর ফলাফলের উপর নির্ভর করতে হবে। আসুন এই কোডটি একবার দেখুন:

synchronized (synchronizedMap) {
    if (synchronizedMap.containsKey(key)) {
        synchronizedMap.get(key).add(value);
    }
    else {
        List<String> valuesList = new ArrayList<String>();
        valuesList.add(value);
        synchronizedMap.put(key, valuesList);
    }
}

এই কোডে

synchronizedMap.get(key).add(value);

এবং

synchronizedMap.put(key, valuesList);

পদ্ধতি কলগুলি পূর্ববর্তী ফলাফলের উপর নির্ভর করে

synchronizedMap.containsKey(key)

পদ্ধতি কল।

পদ্ধতি কলগুলির ক্রমটি যদি সিঙ্ক্রোনাইজ না করা হত তবে ফলাফলটি ভুল হতে পারে। উদাহরণস্বরূপ thread 1পদ্ধতি নির্বাহ করা হয় addToMap()এবং thread 2পদ্ধতি নির্বাহ করা হয় doWork() উপর পদ্ধতি কল ক্রমsynchronizedMap বস্তু হতে পারে নিম্নরূপ: Thread 1পদ্ধতি মৃত্যুদন্ড কার্যকর করেনি

synchronizedMap.containsKey(key)

এবং ফলাফল "true "। এর পরে অপারেটিং সিস্টেম এক্সিকিউশন কন্ট্রোল এ পরিবর্তন করে thread 2এবং এটি কার্যকর করে

synchronizedMap.remove(key)

এর পরে এক্সিকিউশন কন্ট্রোলটি আবার চালু করা হয়েছে thread 1 এবং উদাহরণস্বরূপ এটি কার্যকর করা হয়েছে uted

synchronizedMap.get(key).add(value);

বিশ্বাস করে synchronizedMapঅবজেক্টটিতে রয়েছে keyএবং NullPointerExceptionফেলে দেওয়া synchronizedMap.get(key) হবে কারণ ফিরে আসবে null। যদি synchronizedMapঅবজেক্টে পদ্ধতি কলগুলির ক্রমটি একে অপরের ফলাফলের উপর নির্ভর করে না তবে আপনার ক্রমটি সিঙ্ক্রোনাইজ করার দরকার নেই। উদাহরণস্বরূপ আপনার এই ক্রমটি সিঙ্ক্রোনাইজ করার দরকার নেই:

synchronizedMap.put(key1, valuesList1);
synchronizedMap.put(key2, valuesList2);

এখানে

synchronizedMap.put(key2, valuesList2);

পদ্ধতি কল পূর্ববর্তী ফলাফলের উপর নির্ভর করে না

synchronizedMap.put(key1, valuesList1);

পদ্ধতি কল (কিছু থ্রেড দুটি পদ্ধতির কলগুলির মধ্যে হস্তক্ষেপ করেছে এবং উদাহরণস্বরূপ এটি সরিয়ে ফেলেছে তা বিবেচ্য নয় key1)।


4

এটি আমার কাছে সঠিক দেখাচ্ছে। আমি যদি কিছু পরিবর্তন করতে চাই তবে আমি কালেকশন.সিনক্রোনাইজড ম্যাপ () ব্যবহার করা বন্ধ করে দিয়েছিলাম এবং কেবল এটি পরিষ্কার করার জন্য সমস্ত কিছু একইভাবে সিঙ্ক্রোনাইজ করব।

এছাড়াও, আমি প্রতিস্থাপন করব

  if (synchronizedMap.containsKey(key)) {
    synchronizedMap.get(key).add(value);
  }
  else {
    List<String> valuesList = new ArrayList<String>();
    valuesList.add(value);
    synchronizedMap.put(key, valuesList);
  }

সঙ্গে

List<String> valuesList = synchronziedMap.get(key);
if (valuesList == null)
{
  valuesList = new ArrayList<String>();
  synchronziedMap.put(key, valuesList);
}
valuesList.add(value);

4
করণীয়। আমি এটা পাবেন না কেন আমরা ব্যবহার করা উচিত Collections.synchronizedXXX()API গুলি সিঙ্ক্রোনাইজ করতে কিছু বস্তুর উপর (যা বেশিরভাগ ক্ষেত্রেই শুধু সংগ্রহে নিজেই হবে) আমাদের প্রতিদিন অ্যাপ্লিকেশনের যুক্তিবিজ্ঞান আমরা এখনও আছে
kellogs

3

আপনি যেভাবে সিঙ্ক্রোনাইজ করেছেন তা সঠিক। তবে একটি ধরা আছে

  1. সংগ্রহের কাঠামোর দ্বারা সরবরাহিত সিঙ্ক্রোনাইজড র‍্যাপারটি নিশ্চিত করে যে পদ্ধতিটি কলটি আই / অ্যাড / গেইট / অন্তর্ভুক্তটি পারস্পরিক একচেটিয়াভাবে চলবে।

তবে বাস্তব বিশ্বে আপনি মানটি দেওয়ার আগে সাধারণত মানচিত্রটি জিজ্ঞাসা করবেন। সুতরাং আপনার দুটি ক্রিয়াকলাপ করতে হবে এবং তাই একটি সিঙ্ক্রোনাইজড ব্লক প্রয়োজন। সুতরাং আপনি যেভাবে এটি ব্যবহার করেছেন তা সঠিক। যাহোক.

  1. আপনি সংগ্রহের কাঠামোতে মানচিত্রের একসাথে বাস্তবায়ন ব্যবহার করতে পারেন। 'সমকালীন হ্যাশম্যাপ' সুবিধাটি

ক। এটিতে একটি এপিআই 'পুটআইফএবসেন্ট' রয়েছে যা একই জিনিসগুলি আরও কার্যকরভাবে করবে।

খ। এর দক্ষতা: ডি কোকোর্নাম্যাপ কেবল কীগুলি লক করে তাই এটি পুরো মানচিত্রের বিশ্বকে অবরুদ্ধ করে না। যেখানে আপনি কীগুলি পাশাপাশি মানগুলি অবরুদ্ধ করেছেন।

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


2

পরীক্ষা করে দেখুন গুগল সংগ্রহগুলি ' Multimapযেমন পৃষ্ঠায় 28 এই উপস্থাপনা

আপনি যদি কোনও কারণে সেই লাইব্রেরিটি ব্যবহার করতে না পারেন তবে ConcurrentHashMapপরিবর্তে ব্যবহারের কথা বিবেচনা করুন SynchronizedHashMap; এটির একটি নিফটি putIfAbsent(K,V)পদ্ধতি রয়েছে যা দিয়ে আপনি যদি না ইতিমধ্যে উপাদান তালিকা তালিকায় ইতিমধ্যে না রেখে যোগ করতে পারেন। এছাড়াও, CopyOnWriteArrayListযদি আপনার ব্যবহারের ধরণগুলি এরকমভাবে ওয়ারেন্ট দেয় তবে মানচিত্রের মানগুলির জন্য ব্যবহার করার বিষয়টি বিবেচনা করুন ।

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