Volatile Keyword এর ব্যবহার এবং প্রয়োজনীয়তা

Java Memory Model (JMM) - জাভা কনকারেন্সি (Java Concurrency) - Java Technologies

433

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


volatile এর প্রধান বৈশিষ্ট্য

  1. মেমরি ভিজিবিলিটি (Memory Visibility):
    • একটি volatile ভ্যারিয়েবলের মান যখন একটি থ্রেড পরিবর্তন করে, তখন তা অন্য থ্রেডের কাছে অবিলম্বে দৃশ্যমান হয়।
    • এটি মেমরি ব্যারিয়ার ব্যবহার করে ভ্যালু আপডেটকে মেমোরিতে সিঙ্ক্রোনাইজ করে।
  2. ইনস্ট্রাকশন রিঅর্ডারিং প্রতিরোধ:
    • volatile নিশ্চিত করে যে কম্পাইলার বা প্রসেসর ইনস্ট্রাকশনগুলোর ক্রম পরিবর্তন করবে না।

volatile এর প্রয়োজনীয়তা

volatile ব্যবহার তখন গুরুত্বপূর্ণ যখন:

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

volatile এর ব্যবহার

১. সাধারণ উদাহরণ: ফ্ল্যাগ ভ্যারিয়েবল

class VolatileExample {
    private static volatile boolean running = true;

    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (running) {
                System.out.println("Thread is running...");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("Thread stopped.");
        });

        thread.start();

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        running = false; // থ্রেড বন্ধ করার সিগন্যাল
        System.out.println("Main thread set running to false.");
    }
}

ব্যাখ্যা:

  • running একটি volatile ভ্যারিয়েবল। এটি নিশ্চিত করে যে যখন একটি থ্রেড মান পরিবর্তন করে, অন্য থ্রেড তৎক্ষণাৎ পরিবর্তনটি দেখতে পায়।

২. ইনস্ট্রাকশন রিঅর্ডারিং প্রতিরোধ

class VolatileReorderingExample {
    private static volatile boolean flag = false;
    private static int value = 0;

    public static void main(String[] args) {
        Thread writer = new Thread(() -> {
            value = 42;   // স্টেপ ১
            flag = true;  // স্টেপ ২
        });

        Thread reader = new Thread(() -> {
            if (flag) {
                System.out.println("Value: " + value); // সবসময় 42 হওয়া উচিত
            }
        });

        writer.start();
        reader.start();
    }
}

ব্যাখ্যা:

  • volatile flag নিশ্চিত করে যে value = 42 এর পরে flag = true এক্সিকিউট হবে এবং ইনস্ট্রাকশন রিঅর্ডারিং এড়ানো হবে।

volatile এর সীমাবদ্ধতা

  1. Atomicity নিশ্চিত করে না:

    • volatile কেবল মেমরি ভিজিবিলিটি নিশ্চিত করে। এটি অপারেশনগুলোকে পরমাণুকরণ (atomic) করে না।
    • যেমন, count++ একটি volatile ভ্যারিয়েবলে থ্রেড-সেফ নয়।

    সমাধান: AtomicInteger বা synchronized ব্যবহার করতে হবে।

  2. লকিং এড়ানো যায় না:
    • যখন জটিল ডেটা স্ট্রাকচারের জন্য থ্রেড-সেফটি প্রয়োজন, তখন লকিং ব্যবহার করতে হতে পারে।

Atomicity সমস্যা উদাহরণ

class NonAtomicVolatileExample {
    private static volatile int counter = 0;

    public static void main(String[] args) {
        Thread incrementer1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter++; // Not thread-safe
            }
        });

        Thread incrementer2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter++; // Not thread-safe
            }
        });

        incrementer1.start();
        incrementer2.start();

        try {
            incrementer1.join();
            incrementer2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final Counter Value: " + counter); // ফলাফল অপ্রত্যাশিত হতে পারে
    }
}

সমাধান: AtomicInteger ব্যবহার করুন।

import java.util.concurrent.atomic.AtomicInteger;

class AtomicExample {
    private static AtomicInteger counter = new AtomicInteger(0);

    public static void main(String[] args) {
        Thread incrementer1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.incrementAndGet();
            }
        });

        Thread incrementer2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.incrementAndGet();
            }
        });

        incrementer1.start();
        incrementer2.start();

        try {
            incrementer1.join();
            incrementer2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final Counter Value: " + counter.get()); // ফলাফল সঠিক
    }
}

কখন volatile ব্যবহার করবেন?

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

  • volatile একটি লাইটওয়েট মেকানিজম যা মেমরি ভিজিবিলিটি নিশ্চিত করে।
  • এটি রিড এবং রাইট অপারেশনের মধ্যে ইনস্ট্রাকশন রিঅর্ডারিং প্রতিরোধ করে।
  • যদিও এটি থ্রেড-সেফটি নিশ্চিত করে, এটি পরমাণুকরণ (atomicity) নিশ্চিত করে না। জটিল পরিস্থিতিতে synchronized বা Atomic ক্লাস ব্যবহার করা উচিত।
Content added By
Promotion

Are you sure to start over?

Loading...