জাভা মেমরি মডেলের পরিচিতি

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

আসল জাভা মেমরি মডেল (যা, বিশেষ করে, "পারকোলোকাল মেমরি" বোঝায়), 1995 সালে বিকশিত হয়েছিল, এটি একটি ব্যর্থতা হিসাবে বিবেচিত হয়: কোড সুরক্ষার গ্যারান্টি না হারিয়ে অনেক অপ্টিমাইজেশন করা যায় না। বিশেষত, মাল্টি-থ্রেডেড "একক" লেখার জন্য বেশ কয়েকটি বিকল্প রয়েছে:

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

অতএব, মেমরি মেকানিজম পুনরায় ডিজাইন করা হয়েছে। 2005 সালে, জাভা 5 প্রকাশের সাথে সাথে, একটি নতুন পদ্ধতি উপস্থাপন করা হয়েছিল, যা জাভা 14 প্রকাশের সাথে আরও উন্নত হয়েছিল।

নতুন মডেল তিনটি নিয়মের উপর ভিত্তি করে:

নিয়ম #1 : একক-থ্রেডেড প্রোগ্রাম ছদ্ম-ক্রমিকভাবে চলে। এর অর্থ: বাস্তবে, প্রসেসর প্রতি ঘড়িতে বেশ কয়েকটি ক্রিয়াকলাপ সম্পাদন করতে পারে, একই সময়ে তাদের ক্রম পরিবর্তন করে, তবে, সমস্ত ডেটা নির্ভরতা রয়ে যায়, তাই আচরণটি অনুক্রমিক থেকে আলাদা হয় না।

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

এবং নিয়ম নম্বর 3 : বাকি ঘটনাগুলি ক্রমানুসারে সম্পাদিত হয়, যদি সেগুলি একটি কঠোর আংশিক আদেশ সম্পর্ক দ্বারা সংযুক্ত থাকে "আগে কার্যকর হয়" ( আগে ঘটে )।

আগে ঘটে

লেসলি ল্যামপোর্ট এর আগে হ্যাপেনসের ধারণা নিয়ে এসেছিলেন । এটি একটি কঠোর আংশিক আদেশ সম্পর্ক যা পারমাণবিক কমান্ডের মধ্যে প্রবর্তিত হয়েছে (++ এবং -- পারমাণবিক নয়) এবং এর অর্থ "শারীরিকভাবে আগে" নয়।

এটি বলে যে দ্বিতীয় দলটি প্রথমের দ্বারা করা পরিবর্তনগুলির "জানে" থাকবে।

আগে ঘটে

উদাহরণস্বরূপ, এই ধরনের ক্রিয়াকলাপের জন্য অন্যটির আগে একটি কার্যকর করা হয়:

সিঙ্ক্রোনাইজেশন এবং মনিটর:

  • মনিটর ক্যাপচার করা ( লক পদ্ধতি , সিঙ্ক্রোনাইজড স্টার্ট) এবং এর পরে একই থ্রেডে যা ঘটবে।
  • মনিটরের প্রত্যাবর্তন (পদ্ধতি আনলক , সিঙ্ক্রোনাইজের শেষ) এবং এর আগে একই থ্রেডে যা ঘটবে।
  • মনিটর ফিরিয়ে আনা এবং তারপর অন্য থ্রেড দ্বারা ক্যাপচার করা।

লেখা এবং পড়া:

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

বস্তু রক্ষণাবেক্ষণ:

  • স্থির আরম্ভ এবং অবজেক্টের যেকোন দৃষ্টান্ত সহ যেকোনো ক্রিয়া।
  • কনস্ট্রাক্টরের চূড়ান্ত ক্ষেত্রগুলিতে লেখা এবং কনস্ট্রাক্টরের পরে সবকিছু। একটি ব্যতিক্রম হিসাবে, ঘটে-আগে সম্পর্কটি অন্য নিয়মের সাথে ট্রানজিটিভভাবে সংযোগ করে না এবং তাই একটি আন্তঃ-থ্রেড রেস সৃষ্টি করতে পারে।
  • অবজেক্টের সাথে যে কোন কাজ এবং চূড়ান্ত করুন()

স্ট্রিম পরিষেবা:

  • একটি থ্রেড এবং থ্রেডের যেকোনো কোড শুরু করা হচ্ছে।
  • থ্রেড এবং থ্রেডের যেকোনো কোড সম্পর্কিত ভেরিয়েবল জিরো করা।
  • থ্রেডে কোড এবং join() ; থ্রেডে কোড এবং isAlive() == মিথ্যা
  • interrupt() থ্রেড এবং সনাক্ত করুন যে এটি বন্ধ হয়ে গেছে।

কাজের সূক্ষ্মতার আগে ঘটে

একই মনিটর অর্জন করার আগে একটি ঘটতে-আগে মনিটর প্রকাশ করা হয়। এটি লক্ষণীয় যে এটি মুক্তি, এবং প্রস্থান নয়, অর্থাৎ, অপেক্ষা করার সময় আপনাকে নিরাপত্তার বিষয়ে চিন্তা করতে হবে না।

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

public class Keeper {
    private Data data = null;

    public Data getData() {
        synchronized(this) {
            if(data == null) {
                data = new Data();
            }
        }

        return data;
    }
}

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

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

সুতরাং, আমাদের ডাবল-লকিং রামগুলিতে ফিরে আসি। উদ্বায়ী ব্যবহার করে, আপনি এই মত পরিস্থিতি ঠিক করতে পারেন:

public class Keeper {
    private volatile Data data = null;

    public Data getData() {
        if(data == null) {
            synchronized(this) {
                if(data == null) {
                    data = new Data();
                }
            }
        }
        return data;
    }
}

এখানে আমরা এখনও একটি লক আছে, কিন্তু শুধুমাত্র যদি ডেটা == শূন্য হয়। আমরা উদ্বায়ী রিড ব্যবহার করে অবশিষ্ট কেস ফিল্টার আউট. সঠিকতা নিশ্চিত করা হয় যে উদ্বায়ী স্টোরটি ঘটে - উদ্বায়ী পড়ার আগে, এবং কনস্ট্রাক্টরে ঘটে যাওয়া সমস্ত ক্রিয়াকলাপ যে কেউ ক্ষেত্রের মান পড়ে তার কাছে দৃশ্যমান হয়।