কি জন্য উদ্বায়ী কীওয়ার্ড দরকারী


672

আজ কাজের সময়ে, আমি volatileজাভাতে মূল শব্দটি পেলাম । এর সাথে খুব বেশি পরিচিত না হয়ে, আমি এই ব্যাখ্যাটি পেয়েছি:

জাভা তত্ত্ব এবং অনুশীলন: অস্থিরতা পরিচালনা করা

এই নিবন্ধটিতে কীওয়ার্ডটি বিশদটি বিশদে ব্যাখ্যা করা হয়েছে, আপনি কি কখনও এটি ব্যবহার করেছেন বা আপনি কি এমন কোনও ক্ষেত্রে দেখতে পাচ্ছেন যাতে আপনি এই কীওয়ার্ডটি সঠিকভাবে ব্যবহার করতে পারবেন?

উত্তর:


742

volatileস্মৃতি দৃশ্যমানতার জন্য শব্দার্থবিজ্ঞান রয়েছে। মূলত, volatileকোনও লেখার ক্রিয়া সম্পূর্ণ হওয়ার পরে কোনও ক্ষেত্রের মান সমস্ত পাঠকের কাছে (বিশেষত অন্যান্য থ্রেড) দৃশ্যমান হয়। ছাড়া volatileপাঠকরা কিছু অ-আপডেট হওয়া মান দেখতে পেতেন।

আপনার প্রশ্নের উত্তর দিতে: হ্যাঁ, volatileকিছু কোড লুপ চালিয়ে যায় কিনা তা নিয়ন্ত্রণ করতে আমি একটি পরিবর্তনশীল ব্যবহার করি use লুপটি volatileমানটি পরীক্ষা করে এবং তা চলতে থাকে truefalse"স্টপ" পদ্ধতিতে কল করে শর্তটি সেট করা যেতে পারে । falseস্টপ পদ্ধতিটি কার্যকর করার পরে মানটি পরীক্ষা করে লুপটি দেখে এবং শেষ হয়।

" জাভা কনকুরেন্সি ইন প্র্যাকটিস " বইটি , যা আমি অত্যন্ত সুপারিশ করি, এর একটি ভাল ব্যাখ্যা দেয় volatile। এই বইটি একই ব্যক্তি লিখেছেন যিনি আইবিএম নিবন্ধ লিখেছিলেন যা প্রশ্নের মধ্যে উল্লেখ করা হয়েছে (আসলে, তিনি তার নিবন্ধটি নীচে তার বইটি উদ্ধৃত করেছেন)। আমার ব্যবহারটি volatileতার নিবন্ধটিকে "প্যাটার্ন 1 স্ট্যাটাস ফ্ল্যাগ" বলে।

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


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

46
নতুনদের জন্য, আমি আপনাকে কিছু কোড (দয়া করে?) দিয়ে প্রদর্শনের জন্য অনুরোধ করব
হাংরি ব্লু দেব

6
প্রশ্নের সাথে লিঙ্কিত নিবন্ধটির কোড উদাহরণ রয়েছে।
গ্রেগ ম্যাটেস

আমার মনে হয় 'হেনেসি এবং প্যাটারসন' লিঙ্কটি নষ্ট হয়ে গেছে। এবং 'জাভা মেমরি মডেল' এর লিঙ্কটি আসলে ওরাকলের জাভা ল্যাঙ্গুয়েজ স্পেসিফিকেশন 'অধ্যায় 17. থ্রেডস এবং লকস' এ নিয়ে যায়।
ক্রিস

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

177

"... অস্থির সংশোধক গ্যারান্টি দেয় যে কোনও ক্ষেত্র পড়বে যে কোনও থ্রেড সর্বাধিক লিখিত মানটি দেখতে পাবে” " - জোশ ব্লচ

আপনি যদি ব্যবহারের কথা ভাবছেন volatileতবে প্যাকেজটি পড়ুন java.util.concurrentযা পারমাণবিক আচরণের সাথে সম্পর্কিত।

একটি একক প্যাটার্নে উইকিপিডিয়া পোস্ট ব্যবহারে অস্থির দেখায়।


18
কেন volatileএবং synchronizedকীওয়ার্ড উভয় আছে ?
ptkato

5
সিঙ্গেলন প্যাটার্নে উইকিপিডিয়া নিবন্ধটি অনেক পরিবর্তন হয়েছে এবং volatileএখন পর্যন্ত উদাহরণটির উল্লেখ নেই। এটি একটি সংরক্ষণাগারিত সংস্করণে পাওয়া যাবে ।
বিএসপিপি

1
@ptkato এই দুটি কীওয়ার্ড সম্পূর্ণ ভিন্ন উদ্দেশ্যে পরিবেশন করেছে, সুতরাং প্রশ্নটি তুলনা হিসাবে খুব বেশি বোঝা যায় না, যদিও তারা উভয়ই একযোগের সাথে সম্পর্কিত। এটি "কেন voidএবং publicকীওয়ার্ড উভয়ই আছে" বলার মতো ।
ডেভিডস

134

সম্পর্কে গুরুত্বপূর্ণ বিষয় volatile:

  1. জাভাতে সিঙ্ক্রোনাইজেশন জাভা কীওয়ার্ড synchronizedএবং ব্যবহার করে সম্ভবvolatile এবং কেশ।
  2. জাভাতে, আমরা synchronizedভেরিয়েবল রাখতে পারি না । synchronizedভেরিয়েবল সহ কীওয়ার্ড ব্যবহার করা অবৈধ এবং এর ফলে সংকলন ত্রুটি হবে। পরিবর্তে ব্যবহার করুনsynchronized জাভা পরিবর্তনশীল, আপনি জাভা ব্যবহার করতে পারেন volatileমান পড়তে পরিবর্তনশীল, যা জেভিএম থ্রেড নির্দেশ দেওয়া হবেvolatile প্রধান মেমরি থেকে পরিবর্তনশীল এবং এটি স্থানীয়ভাবে ক্যাশে না।
  3. যদি কোনও ভেরিয়েবল একাধিক থ্রেডের মধ্যে ভাগ না করা হয় তবে volatileকীওয়ার্ডটি ব্যবহার করার দরকার নেই ।

সূত্র

এর ব্যবহারের উদাহরণ volatile:

public class Singleton {
    private static volatile Singleton _instance; // volatile variable
    public static Singleton getInstance() {
        if (_instance == null) {
            synchronized (Singleton.class) {
                if (_instance == null)
                    _instance = new Singleton();
            }
        }
        return _instance;
    }
}

প্রথম অনুরোধটি আসার সময় আমরা অলসভাবে উদাহরণ তৈরি করছি।

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

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

উপসংহার : volatileকীওয়ার্ডটি থ্রেডগুলির মধ্যে মেমরির বিষয়বস্তু যোগাযোগ করার জন্যও ব্যবহৃত হয়।

অস্থির ছাড়া ব্যবহারের উদাহরণ:

public class Singleton{    
    private static Singleton _instance;   //without volatile variable
    public static Singleton getInstance(){   
          if(_instance == null){  
              synchronized(Singleton.class){  
               if(_instance == null) _instance = new Singleton(); 
      } 
     }   
    return _instance;  
    }

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

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

volatileজাভা ব্যবহার :

ব্যর্থ-দ্রুত পুনরাবৃত্তকারীরা সাধারণতvolatile তালিকা তালিকার একটি কাউন্টার ব্যবহার করে প্রয়োগ করা হয় ।

  • তালিকা আপডেট করা হলে, কাউন্টারটি বাড়ানো হয়।
  • যখন একটি Iterator তৈরি করা হয়, কাউন্টারটির বর্তমান মানটি Iteratorবস্তুটিতে এম্বেড করা হয় ।
  • যখন একটি Iterator অপারেশন করা হয়, তখন পদ্ধতিটি দুটি পাল্টা মানগুলির সাথে তুলনা করে এবং ConcurrentModificationExceptionসেগুলি পৃথক হলে একটি নিক্ষেপ করে ।

ব্যর্থ-নিরাপদ পুনরাবৃত্তিগুলির বাস্তবায়ন সাধারণত হালকা ওজন। তারা সাধারণত নির্দিষ্ট তালিকা প্রয়োগের ডেটা স্ট্রাকচারের বৈশিষ্ট্যের উপর নির্ভর করে। কোনও সাধারণ প্যাটার্ন নেই।


2
"ব্যর্থ-ফাস্ট iterators সাধারণত একটি উদ্বায়ী কাউন্টার ব্যবহার প্রয়োগ করা হয়" - আর যদি খুবই ব্যয়বহুল: bugs.java.com/bugdatabase/view_bug.do?bug_id=6625725
Vsevolod Golovanov

_অনস্ট্যান্সের জন্য ডাবল চেকিং কি নিরাপদ? আমি ভেবেছিলাম যে তারা অস্থিতিশীল হয়েও নিরাপদ নয়
ডেক্সটার 21

"যা জেভিএম থ্রেডগুলিকে প্রধান স্মৃতি থেকে অস্থায়ী পরিবর্তনশীলটির মান পড়তে নির্দেশ দেয় এবং স্থানীয়ভাবে এটি ক্যাশে করে না।" ভাল কথা
হুমায়ূন আহমেদ

থ্রেড-সুরক্ষার জন্য এক সাথে যেতে পারে private static final Singleton _instance;
Chris311

53

volatile থ্রেড থামাতে খুব দরকারী।

আপনার নিজের থ্রেডগুলি লিখতে হবে এমনটি নয়, জাভা 1.6 টিতে প্রচুর চমৎকার থ্রেড পুল রয়েছে। তবে আপনি যদি নিশ্চিত হন যে আপনার কোনও থ্রেড প্রয়োজন, তবে এটি কীভাবে বন্ধ করবেন তা আপনার জানতে হবে।

থ্রেডের জন্য আমি যে প্যাটার্নটি ব্যবহার করি তা হ'ল:

public class Foo extends Thread {

  private volatile boolean close = false;

  public void run() {
    while(!close) {
      // do work
    }
  }
  public void close() {
    close = true;
    // interrupt here if needed
  }
}

উপরের কোড বিভাগে, যখন লুপটিতে থ্রেড পঠন closeকল করে তার থেকে আলাদাclose() । অস্থিরতা ছাড়াই, লুপটি চালিত থ্রেডটি কখনও বন্ধ হতে পারে না।

কীভাবে সিঙ্ক্রোনাইজেশনের দরকার নেই তা লক্ষ্য করুন


2
আমি এমনকি কেন এটি প্রয়োজন তা অবাক। অন্য থ্রেডগুলি এই থ্রেডের স্থিতি পরিবর্তন সম্পর্কে এমনভাবে প্রতিক্রিয়া দেখাতে হবে যে থ্রেডগুলির সমন্বয়সাধনের ঝুঁকির মধ্যে রয়েছে কেবল তখনই কি তা প্রয়োজনীয় নয়?
জোরি

27
@ জোরি, আপনার অস্থির প্রয়োজন কারণ লুপের মধ্যে থ্রেড রিডিং কাছাকাছি কল করা () থেকে পৃথক। অস্থিরতা ছাড়াই, লুপটি চালিত থ্রেডটি কখনও বন্ধ হতে পারে না।
পাইরোলিস্টিকাল

আপনি কি বলবেন যে থ্রেডটি থামিয়ে দেওয়া বা থ্রেড # বাধা () এবং থ্রেড # ইস্ট ইন্ডারড্রপড () পদ্ধতি ব্যবহার করার মধ্যে একটি সুবিধা আছে?
রিকার্ডো বেলচিয়ের

2
@ পাইরোলিস্টিকাল - আপনি কি থ্রেডটি বাস্তবে কোনও পরিবর্তন দেখেন নি ? বা নির্ভরযোগ্যভাবে যে সমস্যাটি ট্রিগার করতে আপনি উদাহরণটি প্রসারিত করতে পারেন? আমি কৌতূহলী কারণ আমি জানি যে আমি কোডটি ব্যবহার করেছি (এবং অন্যদের ব্যবহার করতে দেখেছি) যা মূলত উদাহরণের সাথে সাদৃশ্যপূর্ণ তবে volatileকীওয়ার্ড ছাড়াই এবং সর্বদা এটি ঠিকঠাক কাজ করে বলে মনে হয়।
অ্যারোথ

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

31

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


27

মূলশব্দ সহ ঘোষিত একটি চলকটির volatileদুটি প্রধান গুণ রয়েছে যা এটিকে বিশেষ করে তোলে।

  1. আমাদের যদি একটি অস্থির পরিবর্তনশীল থাকে তবে এটি কোনও থ্রেড দ্বারা কম্পিউটারের (মাইক্রোপ্রসেসর) ক্যাশে মেমরিতে ক্যাশে করা যায় না। অ্যাক্সেস সর্বদা প্রধান স্মৃতি থেকে ঘটে।

  2. যদি কোনও লিখন অপারেশন যদি কোনও অস্থির পরিবর্তনশীল হয় এবং হঠাৎ একটি পঠন অপারেশন অনুরোধ করা হয় তবে এটি নিশ্চয়তা দেয় যে রিড অপারেশন আগে রাইটিং অপারেশন শেষ হয়ে যাবে

উপরোক্ত দুটি গুন তা হ্রাস করুন

  • একটি অস্থির ভেরিয়েবল পড়া সমস্ত থ্রেড অবশ্যই সর্বশেষতম মানটি পড়বে। কারণ কোনও ক্যাশেড মান এটি দূষিত করতে পারে না। এবং এছাড়াও পড়ার অনুরোধটি কেবল বর্তমান রাইটিং অপারেশন সমাপ্তির পরে অনুমোদিত হবে।

এবং অন্যদিকে,

  • আমি যদি উল্লিখিত # 2 টি আরও তদন্ত করে দেখি, আমরা দেখতে পাচ্ছি যে volatileকীওয়ার্ডটি একটি ভাগ করা পরিবর্তনশীল বজায় রাখার জন্য একটি আদর্শ উপায় যার পাঠক থ্রেডের 'এন' সংখ্যা রয়েছে এবং এটিতে অ্যাক্সেসের জন্য কেবল একটি লেখক থ্রেড রয়েছে । একবার আমরা volatileকীওয়ার্ডটি যুক্ত করলে এটি হয়ে যায়। থ্রেড সুরক্ষা সম্পর্কে অন্য কোনও ওভারহেড নেই।

Conversly,

আমরা এককভাবে কীওয়ার্ডটি ব্যবহার করতে পারি নাvolatile , একটি ভাগ করা ভেরিয়েবলকে সন্তুষ্ট করতে যার একাধিক লেখক থ্রেড এতে প্রবেশ করে


3
এটি উদ্বায়ী এবং সিঙ্ক্রোনাইজড মধ্যে পার্থক্য ব্যাখ্যা করে।
আজাই

13

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


এটিকে আরও সুস্পষ্ট করার জন্য, বুলিয়ান অস্থিরতা স্থাপনের দরকার নেই, কারণ একটি বুলিয়ান পড়তে এবং লেখার আগেই পারমাণবিক।
কাই ওয়াং

2
@ কাইওয়্যাং-এ আপনাকে পারমাণবিকতার জন্য বুলিয়ানগুলিতে অস্থিরতা ব্যবহার করার দরকার নেই। তবে আপনি অবশ্যই দৃশ্যমানতার কারণে হতে পারেন। আপনি কি বলতে চাইছেন?
সুসানডাব্লু

12

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


10

আমার মতে, থ্রেড থামানো ছাড়া দুটি গুরুত্বপূর্ণ পরিস্থিতি যেখানে অস্থায়ী কীওয়ার্ড ব্যবহৃত হয়:

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

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

5

আপনি যদি কোনও মাল্টিথ্রেডেড অ্যাপ্লিকেশন বিকাশ করে থাকেন তবে আপনাকে 'ভোল্টাইল' কীওয়ার্ড বা 'সিঙ্ক্রোনাইজড' এবং অন্য কোনও একত্রীকরণ নিয়ন্ত্রণ সরঞ্জাম এবং কৌশলগুলি ব্যবহার করতে হবে। যেমন অ্যাপ্লিকেশন উদাহরণ ডেস্কটপ অ্যাপ্লিকেশন।

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

সুতরাং, জাভা বিকাশের বেশিরভাগ ক্ষেত্রে যেখানে অ্যাপ্লিকেশনটি একটি ওয়েব অ্যাপ্লিকেশন এবং আইওসি ফ্রেমওয়ার্ক যেমন স্প্রিং বা ইজেবি ব্যবহার করে, আপনাকে 'অস্থিরতা' ব্যবহার করার প্রয়োজন হবে না।


5

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

package io.netty.example.telnet;

import java.util.ArrayList;
import java.util.List;

public class Main {

    public static volatile  int a = 0;
    public static void main(String args[]) throws InterruptedException{

        List<Thread> list = new  ArrayList<Thread>();
        for(int i = 0 ; i<11 ;i++){
            list.add(new Pojo());
        }

        for (Thread thread : list) {
            thread.start();
        }

        Thread.sleep(20000);
        System.out.println(a);
    }
}
class Pojo extends Thread{
    int a = 10001;
    public void run() {
        while(a-->0){
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Main.a++;
            System.out.println("a = "+Main.a);
        }
    }
}

এমনকি আপনি অস্থির রাখেন বা না রাখুন ফলাফল সর্বদা পৃথক হবে। তবে আপনি যদি নীচের হিসাবে অ্যাটমিকিন্টিজার ব্যবহার করেন তবে ফলাফলগুলি সর্বদা একই হবে। এটি সিঙ্ক্রোনাইজডের সাথেও একই।

    package io.netty.example.telnet;

    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.atomic.AtomicInteger;

    public class Main {

        public static volatile  AtomicInteger a = new AtomicInteger(0);
        public static void main(String args[]) throws InterruptedException{

            List<Thread> list = new  ArrayList<Thread>();
            for(int i = 0 ; i<11 ;i++){
                list.add(new Pojo());
            }

            for (Thread thread : list) {
                thread.start();
            }

            Thread.sleep(20000);
            System.out.println(a.get());

        }
    }
    class Pojo extends Thread{
        int a = 10001;
        public void run() {
            while(a-->0){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Main.a.incrementAndGet();
                System.out.println("a = "+Main.a);
            }
        }
    }

4

হ্যাঁ, আমি এটি বেশ ব্যবহার করি - এটি মাল্টি-থ্রেড কোডের জন্য খুব দরকারী। আপনি নিবন্ধটি নির্দেশ করেছেন একটি ভাল। যদিও মনে রাখা দুটি গুরুত্বপূর্ণ বিষয় রয়েছে:

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

4

একটি অস্থির ক্ষেত্র অ্যাক্সেস করা প্রতিটি থ্রেড একটি ক্যাশেড মান ব্যবহার করে (সম্ভাব্য) পরিবর্তে চালিয়ে যাওয়ার আগে এর বর্তমান মানটি পড়বে।

কেবল সদস্য পরিবর্তনশীলই অস্থির বা ক্ষণস্থায়ী হতে পারে।


3

অবশ্যই হ্যাঁ. (এবং কেবল জাভাতে নয়, সি সি তেও) থ্রেড লকিংয়ের ওভারহেড উদ্বোধনী কীওয়ার্ড আপনাকে তা নিশ্চিত করতে দেয় যে আপনি যখন বর্তমান মানটি পেয়েছেন এবং ক্যাশেড মান নয় যা সবেমাত্র অন্য থ্রেডে কোনও লেখার দ্বারা অপ্রচলিত হয়েছিল read


3

উদ্বায়ী কিওয়ার্ডের দুটি পৃথক ব্যবহার রয়েছে।

  1. জেভিএমকে রেজিস্টার (ক্যাশে হিসাবে ধরে নেওয়া) থেকে মানগুলি পড়া থেকে আটকায় এবং এর মানটিকে মেমরি থেকে পড়তে বাধ্য করে।
  2. সামঞ্জস্যের ত্রুটিযুক্ত মেমরির ঝুঁকি হ্রাস করে।

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

কোনও ব্যস্ত পতাকাটি ডিভাইসটি ব্যস্ত থাকাকালীন থ্রেডটি চালিয়ে যাওয়া থেকে রোধ করতে ব্যবহৃত হয় এবং পতাকাটি কোনও লক দ্বারা সুরক্ষিত থাকে না:

while (busy) {
    /* do something else */
}

যখন অন্য থ্রেডটি ব্যস্ত পতাকাটি বন্ধ করে দেয় তখন পরীক্ষামূলক থ্রেড চলতে থাকবে :

busy = 0;

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

মেমরি ধারাবাহিকতা ত্রুটির ঝুঁকি হ্রাস করে।

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

মেমরির ধারাবাহিকতা ত্রুটি না করে পড়া, লেখার কৌশলকে পারমাণবিক ক্রিয়া বলা হয়

একটি পারমাণবিক ক্রিয়া এমন এক যা কার্যকরভাবে একবারে ঘটে। পারমাণবিক ক্রিয়া মাঝখানে থামতে পারে না: হয় হয় সম্পূর্ণরূপে হয়, বা এটি মোটেও ঘটে না। অ্যাকশনটি সম্পূর্ণ না হওয়া পর্যন্ত কোনও পারমাণবিক ক্রিয়া সম্পর্কিত কোনও পার্শ্ব প্রতিক্রিয়া দৃশ্যমান নয়।

নীচে এমন ক্রিয়া রয়েছে যা আপনি নির্দিষ্ট করতে পারেন যা পারমাণবিক:

  • পাঠ্য এবং লেখাগুলি রেফারেন্স ভেরিয়েবলের জন্য এবং বেশিরভাগ আদিম ভেরিয়েবলগুলির জন্য (দীর্ঘ এবং ডাবল ব্যতীত সমস্ত ধরণের) পারমাণবিক।
  • পড়া এবং লেখাগুলি অস্থায়ী হিসাবে ঘোষিত সমস্ত চলকগুলির জন্য পারমাণবিক (দীর্ঘ এবং ডাবল ভেরিয়েবল সহ)।

চিয়ার্স!


3

volatileএকজন প্রোগ্রামারের জন্য বলেছেন যে মানটি সর্বদা আপ টু ডেট থাকবে। সমস্যাটি হ'ল মানটি বিভিন্ন ধরণের হার্ডওয়্যার মেমোরিতে সংরক্ষণ করা যায়। উদাহরণস্বরূপ এটি সিপিইউ রেজিস্টার, সিপিইউ ক্যাশে, র‌্যাম হতে পারে ... Uপু রেজিস্টার এবং সিপিইউ ক্যাশে সিপিইউ সম্পর্কিত এবং এটি মাল্টথ্রিডিং এনভিরম্পম্পমেন্টে উদ্ধারকৃত র‌্যামের মত একটি ডেটা ভাগ করতে পারে না can

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

volatileকীওয়ার্ড বলছে যে একটি চলক সরাসরি / র‍্যাম মেমরি থেকে সরাসরি পাঠানো এবং লেখা হবে । এটিতে কিছু গণনার পদচিহ্ন রয়েছে

Java 5volatileসমর্থন দ্বারা প্রসারিত happens-before[সম্পর্কে]

একটি অস্থির ক্ষেত্রের একটি লিখন ঘটে-ক্ষেত্রটি পরবর্তী প্রতিটি পড়ার আগে।

volatileশব্দ নিরাময় নেই একটি race conditionঅবস্থা যখন একাধিক থ্রেড পারেন লিখতে একযোগে কিছু মান। উত্তরটি synchronizedমূলশব্দ [সম্পর্কে]

ফলস্বরূপ এটি কেবল তখনই সুরক্ষিত হয় যখন একটি থ্রেড লিখে এবং অন্যরা কেবল এটি পড়ে readvolatile মানটি

উদ্বায়ী বনাম সিঙ্ক্রোনাইজড


2

অস্থির নিম্নলিখিত অনুসরণ করে।

1> বিভিন্ন থ্রেড দ্বারা উদ্বায়ী ভেরিয়েবলগুলি পড়ুন এবং লিখুন সর্বদা স্মৃতি থেকে থাকে, থ্রেডের নিজস্ব ক্যাশে বা সিপিইউ নিবন্ধ থেকে নয়। সুতরাং প্রতিটি থ্রেড সর্বদা সর্বশেষতম মানটি নিয়ে কাজ করে। 2> 2 টি পৃথক থ্রেড যখন একই দৃষ্টান্ত বা স্থির ভেরিয়েবলের সাথে গাদা হয়ে কাজ করে, তখন অন্যের ক্রিয়াকলাপটি অর্ডারের বাইরে থাকতে পারে। এটিতে জেরেমি ম্যানসনের ব্লগটি দেখুন। তবে উদ্বায়ী এখানে সহায়তা করে।

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

thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3
thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3
thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3

এটি অর্জনের জন্য আমরা নিম্নলিখিত পূর্ণাঙ্গ চলমান কোডটি ব্যবহার করতে পারি।

public class Solution {
    static volatile int counter = 0;
    static int print = 0;
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Thread[] ths = new Thread[4];
        for (int i = 0; i < ths.length; i++) {
            ths[i] = new Thread(new MyRunnable(i, ths.length));
            ths[i].start();
        }
    }
    static class MyRunnable implements Runnable {
        final int thID;
        final int total;
        public MyRunnable(int id, int total) {
            thID = id;
            this.total = total;
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            while (true) {
                if (thID == counter) {
                    System.out.println("thread " + thID + " prints " + print);
                    print++;
                    if (print == total)
                        print = 0;
                    counter++;
                    if (counter == total)
                        counter = 0;
                } else {
                    try {
                        Thread.sleep(30);
                    } catch (InterruptedException e) {
                        // log it
                    }
                }
            }
        }
    }
}

নিম্নলিখিত গিথুব লিঙ্কটিতে একটি রিডমি রয়েছে যা সঠিক ব্যাখ্যা দেয়। https://github.com/sankar4git/volatile_thread_ordering


1

ওরাকল ডকুমেন্টেশন পৃষ্ঠা থেকে , মেমরি ধারাবাহিকতার সমস্যাগুলি সমাধান করতে উদ্বায়ী ভেরিয়েবলের প্রয়োজনীয়তা দেখা দেয়:

উদ্বায়ী ভেরিয়েবলগুলি ব্যবহার করা স্মৃতি ধারাবাহিকতা ত্রুটির ঝুঁকি হ্রাস করে, কারণ কোনও অস্থির ভেরিয়েবলের কোনও লেখাই সেই একই ভেরিয়েবলের পরবর্তী পাঠগুলির সাথে ঘটে যাওয়া সম্পর্ক স্থাপন করে।

এর অর্থ হ'ল কোনও volatileভেরিয়েবলের পরিবর্তনগুলি সর্বদা অন্যান্য থ্রেডে দৃশ্যমান। এর অর্থ এটিও হ'ল যে কোনও থ্রেড যখন একটি অস্থির পরিবর্তনীয় পড়ে তখন এটি কেবল সর্বশেষ পরিবর্তনটিই দেখতে পায় নাvolatile পার্শ্ব প্রতিক্রিয়াও যা পরিবর্তনের দিকে নিয়েছিল।

হিসাবে ব্যাখ্যা Peter Parkerউত্তর, অভাবে volatileপরিবর্তক, প্রতিটি থ্রেড এর স্ট্যাকের পরিবর্তনশীল তাদের নিজস্ব কপি থাকতে পারে। পরিবর্তনশীল হিসাবে হিসাবে তৈরি করে volatile, মেমরি ধারাবাহিকতার সমস্যাগুলি ঠিক করা হয়েছে।

আরও ভাল বোঝার জন্য জেনকভ টিউটোরিয়াল পৃষ্ঠাটি দেখুন ।

অস্থিরতা ব্যবহারের জন্য অস্থিরতা এবং ব্যবহারের ক্ষেত্রে আরও কিছু তথ্যের জন্য এসই সম্পর্কিত প্রশ্নটি দেখুন:

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

একটি ব্যবহারিক ব্যবহারের কেস:

আপনি অনেক থ্রেড, যা উদাহরণস্বরূপ কোনো একটি নির্দিষ্ট বিন্যাসে বর্তমান সময় মুদ্রণ প্রয়োজন আছে: java.text.SimpleDateFormat("HH-mm-ss")। ইয়নের একটি শ্রেণি থাকতে পারে যা বর্তমান সময়কে রূপান্তর SimpleDateFormatকরে এবং প্রতি এক সেকেন্ডের জন্য পরিবর্তনশীল আপডেট করে। অন্যান্য সমস্ত থ্রেডগুলি লগ ফাইলগুলিতে বর্তমান সময়ের মুদ্রণের জন্য কেবল এই অস্থির পরিবর্তনশীলটি ব্যবহার করতে পারে।


1

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


-1

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

যদি পরিবর্তনগুলি 1 টি থ্রেড দ্বারা করা হয় এবং অন্যদের কেবল এই মানটি পড়ার প্রয়োজন হয়, তবে উদ্বায়ীটি উপযুক্ত হবে।


-1

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


-2

volatileভেরিয়েবলের প্রয়োজনীয়তা প্রদর্শনের জন্য নীচে একটি খুব সহজ কোড দেওয়া হয়েছে যা অন্য থ্রেড থেকে থ্রেড এক্সিকিউশন নিয়ন্ত্রণ করতে ব্যবহৃত হয় (এটি যেখানে volatileপ্রয়োজন সেখানে এটি একটি দৃশ্য )।

// Code to prove importance of 'volatile' when state of one thread is being mutated from another thread.
// Try running this class with and without 'volatile' for 'state' property of Task class.
public class VolatileTest {
    public static void main(String[] a) throws Exception {
        Task task = new Task();
        new Thread(task).start();

        Thread.sleep(500);
        long stoppedOn = System.nanoTime();

        task.stop(); // -----> do this to stop the thread

        System.out.println("Stopping on: " + stoppedOn);
    }
}

class Task implements Runnable {
    // Try running with and without 'volatile' here
    private volatile boolean state = true;
    private int i = 0;

    public void stop() {
        state = false;
    } 

    @Override
    public void run() {
        while(state) {
            i++;
        }
        System.out.println(i + "> Stopped on: " + System.nanoTime());
    }
}

কখন volatileব্যবহার করা হয় না: আপনি ' স্টপিং অন: এক্সএক্সএক্সএক্স ' এর পরেও ' স্টপড অন: এক্সএক্সএক্সএক্স ' বার্তাটি দেখতে পাবেন না এবং প্রোগ্রামটি চলতে থাকবে।

Stopping on: 1895303906650500

যখন volatileব্যবহার করা হবে: আপনি অবিলম্বে ' স্টপড অন: এক্সএক্সএক্স ' দেখতে পাবেন ।

Stopping on: 1895285647980000
324565439> Stopped on: 1895285648087300

ডেমো: https://repl.it/repls/SilverAgonizingObjectcode


ডাউনভোটারকে: কেন ডাউনভোট ব্যাখ্যা করবেন? যদি এটি সত্য না হয় তবে কমপক্ষে আমি কী ভুল তা শিখব। আমি এই একই মন্তব্যটি দু'বার যুক্ত করেছি, তবে জানি না কে বার বার মুছে
ফেলছে

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