Atomic Operations এবং Variables

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

470

Atomic Operations কি?

অ্যাটমিক অপারেশন (Atomic Operation) এমন এক ধরনের অপারেশন যা অবিচ্ছিন্নভাবে (indivisible) সম্পন্ন হয়।

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

উদাহরণ:

x = x + 1;

এটি অ্যাটমিক নয়, কারণ এটি তিনটি ধাপে বিভক্ত:

  1. ভেরিয়েবলের মান পড়া (read).
  2. নতুন মান যোগ করা (modify).
  3. ভেরিয়েবলে নতুন মান লেখা (write).

Atomic Variables

জাভার java.util.concurrent.atomic প্যাকেজটি Atomic Variables সরবরাহ করে। এগুলো থ্রেড-সেফ অপারেশন নিশ্চিত করে।

  • AtomicInteger
  • AtomicLong
  • AtomicBoolean
  • AtomicReference

সুবিধাসমূহ:

  • থ্রেড-সেফ।
  • সিঙ্ক্রোনাইজড ব্যবহার করার প্রয়োজন নেই।
  • উচ্চ পারফর্মেন্স।

AtomicInteger উদাহরণ

কোড:

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicExample {
    private AtomicInteger count = new AtomicInteger(0);

    public void increment() {
        count.incrementAndGet(); // Atomic increment
    }

    public int getCount() {
        return count.get(); // Atomic get
    }

    public static void main(String[] args) {
        AtomicExample example = new AtomicExample();

        // নতুন থ্রেড তৈরি
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                example.increment();
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                example.increment();
            }
        });

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final Count: " + example.getCount());
    }
}

আউটপুট:

Final Count: 2000

ব্যাখ্যা:

  • incrementAndGet() একটি অ্যাটমিক অপারেশন, যা থ্রেড-সেফ।
  • একাধিক থ্রেড একই সাথে count আপডেট করলেও রেস কন্ডিশন হবে না।

AtomicBoolean উদাহরণ

কোড:

import java.util.concurrent.atomic.AtomicBoolean;

public class AtomicBooleanExample {
    private AtomicBoolean flag = new AtomicBoolean(false);

    public void toggle() {
        flag.set(!flag.get());
    }

    public boolean getFlag() {
        return flag.get();
    }

    public static void main(String[] args) {
        AtomicBooleanExample example = new AtomicBooleanExample();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                example.toggle();
                System.out.println("Thread 1: " + example.getFlag());
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                example.toggle();
                System.out.println("Thread 2: " + example.getFlag());
            }
        });

        t1.start();
        t2.start();
    }
}

AtomicReference উদাহরণ

কোড:

import java.util.concurrent.atomic.AtomicReference;

class User {
    private String name;

    public User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

public class AtomicReferenceExample {
    private AtomicReference<User> user = new AtomicReference<>(new User("Default"));

    public void setUser(User newUser) {
        user.set(newUser); // Atomic set
    }

    public User getUser() {
        return user.get(); // Atomic get
    }

    public static void main(String[] args) {
        AtomicReferenceExample example = new AtomicReferenceExample();

        Thread t1 = new Thread(() -> {
            example.setUser(new User("User1"));
            System.out.println("Thread 1: " + example.getUser().getName());
        });

        Thread t2 = new Thread(() -> {
            example.setUser(new User("User2"));
            System.out.println("Thread 2: " + example.getUser().getName());
        });

        t1.start();
        t2.start();
    }
}

Atomic Operations এর সুবিধা

  1. Thread-Safe:
    • একাধিক থ্রেডের ক্ষেত্রে রেস কন্ডিশন থেকে রক্ষা।
  2. No Synchronization Overhead:
    • synchronized ব্লকের চেয়ে পারফর্মেন্স ভালো।
  3. Lock-Free Mechanism:
    • এটি লক-ফ্রি অপারেশন করে কাজ দ্রুত সম্পন্ন করে।
  4. CAS (Compare-And-Swap):
    • ভ্যালু পরিবর্তনের সময় JDK CAS ব্যবহার করে, যা আরও কার্যকর।

Atomic Operations বনাম Synchronization

বিষয়Atomic OperationsSynchronization
থ্রেড সেফটিCAS দিয়ে নিশ্চিতম্যানুয়াল synchronized দরকার
পারফর্মেন্সদ্রুত (লক-ফ্রি)তুলনামূলক ধীর
লক প্রয়োজনলক-ফ্রিলক দরকার
সহজতাসহজজটিল

Atomic Operations এবং Variables মাল্টি-থ্রেডিং অ্যাপ্লিকেশনে ডেটা নিরাপত্তা এবং পারফর্মেন্স নিশ্চিত করার জন্য অপরিহার্য।

  • ছোট এবং নির্দিষ্ট কার্যক্রমের জন্য Atomic Variables সবচেয়ে ভালো পছন্দ।
  • বড় এবং জটিল কার্যক্রমে synchronization বা অন্যান্য লক মেকানিজম ব্যবহার করা উচিত।
Content added By

Atomicity কি?

Atomicity একটি প্রোগ্রামের এমন বৈশিষ্ট্য যা নিশ্চিত করে যে একটি অপারেশন বা ট্রানজেকশন হয় সম্পূর্ণরূপে এক্সিকিউট হবে অথবা একেবারে হবে না।
এটি "সব অথবা কিছুই নয়" নীতির উপর ভিত্তি করে কাজ করে।

জাভার কনকারেন্সি মডেলে, atomicity নিশ্চিত করে যে একাধিক থ্রেড যখন একই ডেটার উপর কাজ করে, তখন অপারেশনগুলো partial update না করে সম্পূর্ণ সঠিকভাবে কাজ করে।


উদাহরণ: Non-Atomic অপারেশন

ধরা যাক, একটি শেয়ার্ড ইন্টিজার ভেরিয়েবল counter রয়েছে এবং দুটি থ্রেড এটি ইনক্রিমেন্ট করতে চায়। নিচের কোডটি দেখুন:

public class Counter {
    private int counter = 0;

    public void increment() {
        counter++;
    }

    public int getCounter() {
        return counter;
    }
}

এই কোডে counter++ আসলে তিনটি ধাপ সম্পন্ন করে:

  1. ভেরিয়েবলের বর্তমান মান পড়া (load).
  2. একটি মান যোগ করা (add).
  3. ফলাফলটি পুনরায় লিখে ফেলা (store).

যদি দুটি থ্রেড একই সময়ে এই অপারেশনটি এক্সিকিউট করে, তবে তারা একই মান পড়তে পারে এবং একে অপরের আপডেট ওভাররাইট করে। ফলে counter সঠিকভাবে ইনক্রিমেন্ট হয় না।


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

  1. ডেটা ইন্টিগ্রিটি রক্ষা করা:
    শেয়ার্ড ডেটার উপর থ্রেডগুলোর একযোগে অ্যাক্সেসের ফলে ডেটা ইনকনসিস্টেন্সি হতে পারে। Atomicity নিশ্চিত করে যে প্রতিটি থ্রেড একটি শেয়ার্ড রিসোর্সে সম্পূর্ণ অপারেশন চালাতে পারবে।
  2. Race Condition প্রতিরোধ করা:
    একাধিক থ্রেডের মধ্যে সমান্তরাল অ্যাক্সেসের ফলে ডেটার আপডেট ভুল হতে পারে। Atomicity এটি প্রতিরোধ করে।
  3. Deadlock মুক্ত:
    Atomicity নিশ্চিত করলে ডেটা আপডেট করার সময় Deadlock এর ঝুঁকি কম থাকে।
  4. Thread Safety নিশ্চিত করা:
    শেয়ার্ড রিসোর্সের সঠিক ব্যবহারের জন্য Atomicity অপরিহার্য। এটি নিশ্চিত করে যে একাধিক থ্রেড ডেটার উপর একযোগে কাজ করলে সমস্যা হবে না।

Atomicity কিভাবে নিশ্চিত করা যায়?

১. Atomic Classes ব্যবহার করে

জাভাতে java.util.concurrent.atomic প্যাকেজ সরবরাহ করা হয়েছে, যা Thread-safe এবং atomicity নিশ্চিত করে।
যেমন, AtomicInteger, AtomicLong, AtomicReference ইত্যাদি।

import java.util.concurrent.atomic.AtomicInteger;

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

    public void increment() {
        counter.incrementAndGet();
    }

    public int getCounter() {
        return counter.get();
    }

    public static void main(String[] args) {
        AtomicExample example = new AtomicExample();
        example.increment();
        System.out.println("Counter: " + example.getCounter());
    }
}

ব্যাখ্যা:

  • AtomicInteger.incrementAndGet() একক ধাপে মান বৃদ্ধি করে। এটি সম্পূর্ণ Atomic Operation

২. Synchronized ব্লক ব্যবহার করে

Synchronized ব্যবহার করলে এক সময়ে শুধুমাত্র একটি থ্রেড শেয়ার্ড রিসোর্স অ্যাক্সেস করতে পারে। এটি atomicity নিশ্চিত করতে সাহায্য করে।

public class SynchronizedExample {
    private int counter = 0;

    public synchronized void increment() {
        counter++;
    }

    public synchronized int getCounter() {
        return counter;
    }
}

ব্যাখ্যা:

  • synchronized ব্লক নিশ্চিত করে যে increment() অপারেশন চলাকালীন অন্য কোনো থ্রেড রিসোর্সে অ্যাক্সেস করতে পারবে না।

৩. Lock এবং ReentrantLock ব্যবহার করে

java.util.concurrent.locks.Lock ইন্টারফেস ব্যবহার করে atomicity নিশ্চিত করা যায়। এটি synchronized-এর তুলনায় আরো নমনীয়।

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockExample {
    private int counter = 0;
    private Lock lock = new ReentrantLock();

    public void increment() {
        lock.lock();
        try {
            counter++;
        } finally {
            lock.unlock();
        }
    }

    public int getCounter() {
        return counter;
    }
}

ব্যাখ্যা:

  • lock.lock() শেয়ার্ড রিসোর্সে অ্যাক্সেস ব্লক করে, এবং lock.unlock() তা মুক্ত করে।

Atomicity এবং Performance

  1. Performance Trade-off:
    Atomicity নিশ্চিত করার জন্য সিঙ্ক্রোনাইজেশন বা লকিং ব্যবহার করলে পারফরম্যান্স কমে যেতে পারে। এটি বিশেষত উচ্চ কনকারেন্সি পরিস্থিতিতে গুরুত্বপূর্ণ।
  2. Optimized Solutions:
    Atomic classes (যেমন AtomicInteger) লাইটওয়েট এবং পারফরম্যান্সের জন্য উপযুক্ত কারণ এগুলো লক-ফ্রি।

Atomicity নিশ্চিত করার সেরা উপায়

  • ছোট এবং নির্দিষ্ট অপারেশনগুলির জন্য Atomic ক্লাস ব্যবহার করা ভালো।
  • বড় এবং জটিল অপারেশনগুলির জন্য synchronized বা Lock ব্যবহার করতে পারেন।
  • স্পিন-লক বা রিডার-রাইটার লক ব্যবহার করলে পারফরম্যান্স উন্নত হতে পারে।

Atomicity হল জাভা কনকারেন্সির একটি গুরুত্বপূর্ণ বৈশিষ্ট্য যা ডেটার সঠিকতা এবং থ্রেড সেফটি নিশ্চিত করে। এটি ব্যবহারে ডেটার ইনকনসিস্টেন্সি, রেস কন্ডিশন, এবং অন্যান্য কনকারেন্সি সমস্যা এড়ানো যায়। Atomic Classes, synchronized, এবং Lock-এর মতো কৌশলগুলোর মাধ্যমে এটি সহজেই নিশ্চিত করা সম্ভব।

Content added By

জাভার java.util.concurrent.atomic প্যাকেজটি একটি গুরুত্বপূর্ণ কনকারেন্সি টুল যা মাল্টি-থ্রেডেড অ্যাপ্লিকেশনে পরমাণু (atomic) কার্য সম্পাদনের জন্য ব্যবহৃত হয়। এটি Atomic Variable Classes সরবরাহ করে, যা ডেটা ম্যানিপুলেশন অপারেশনগুলিকে atomic (অবিভাজ্য) করে তোলে। এই প্যাকেজটি synchronized ব্লকের বিকল্প হিসেবে ব্যবহৃত হয়, যা পারফরম্যান্স উন্নত করে।


Atomic (পরমাণু) কি?

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


java.util.concurrent.atomic প্যাকেজের ক্লাসসমূহ

১. AtomicInteger

  • একটি int ভেরিয়েবলকে পরমাণু অপারেশন দিয়ে পরিচালনা করার জন্য।
  • থ্রেড-সেইফ increment, decrement, এবং compareAndSet মেথড প্রদান করে।

২. AtomicLong

  • একটি long ভেরিয়েবল পরিচালনা করে একইভাবে যেমন AtomicInteger

৩. AtomicBoolean

  • একটি boolean ভেরিয়েবলকে পরিচালনা করে।

৪. AtomicReference

  • একটি অবজেক্টকে পরমাণু অপারেশন দিয়ে পরিচালনা করতে ব্যবহৃত হয়।

৫. AtomicStampedReference

  • একটি অবজেক্টের সাথে একটি স্ট্যাম্প মান ব্যবহার করে পরিবর্তন নিশ্চিত করে।

৬. AtomicMarkableReference

  • অবজেক্ট পরিবর্তনের জন্য একটি মার্ক বা চিহ্ন ব্যবহার করে।

AtomicInteger উদাহরণ

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicIntegerExample {
    public static void main(String[] args) {
        AtomicInteger atomicInt = new AtomicInteger(0);

        // মান বৃদ্ধি (Increment)
        System.out.println("Initial Value: " + atomicInt.get());
        atomicInt.incrementAndGet(); // ১ যোগ করে মান ফেরত দেয়
        System.out.println("After Increment: " + atomicInt.get());

        // মান হ্রাস (Decrement)
        atomicInt.decrementAndGet(); // ১ কমায় এবং মান ফেরত দেয়
        System.out.println("After Decrement: " + atomicInt.get());

        // নির্দিষ্ট মান সেট করা (Set a value)
        atomicInt.set(5);
        System.out.println("Set Value: " + atomicInt.get());

        // Compare And Set
        boolean isUpdated = atomicInt.compareAndSet(5, 10); // যদি বর্তমান মান ৫ হয়, তাহলে ১০ সেট করে
        System.out.println("Compare and Set Successful: " + isUpdated);
        System.out.println("Updated Value: " + atomicInt.get());
    }
}

আউটপুট:

Initial Value: 0
After Increment: 1
After Decrement: 0
Set Value: 5
Compare and Set Successful: true
Updated Value: 10

AtomicReference উদাহরণ

import java.util.concurrent.atomic.AtomicReference;

public class AtomicReferenceExample {
    public static void main(String[] args) {
        AtomicReference<String> atomicString = new AtomicReference<>("Initial Value");

        System.out.println("Original Value: " + atomicString.get());

        // মান আপডেট করা
        atomicString.set("Updated Value");
        System.out.println("After Set: " + atomicString.get());

        // Compare And Set
        boolean isUpdated = atomicString.compareAndSet("Updated Value", "Final Value");
        System.out.println("Compare and Set Successful: " + isUpdated);
        System.out.println("Updated Value: " + atomicString.get());
    }
}

আউটপুট:

Original Value: Initial Value
After Set: Updated Value
Compare and Set Successful: true
Updated Value: Final Value

AtomicStampedReference উদাহরণ

import java.util.concurrent.atomic.AtomicStampedReference;

public class AtomicStampedReferenceExample {
    public static void main(String[] args) {
        AtomicStampedReference<Integer> stampedRef = new AtomicStampedReference<>(100, 1);

        System.out.println("Initial Value: " + stampedRef.getReference());
        System.out.println("Initial Stamp: " + stampedRef.getStamp());

        // আপডেট করুন
        boolean isUpdated = stampedRef.compareAndSet(100, 200, 1, 2);
        System.out.println("Update Successful: " + isUpdated);
        System.out.println("Updated Value: " + stampedRef.getReference());
        System.out.println("Updated Stamp: " + stampedRef.getStamp());
    }
}

আউটপুট:

Initial Value: 100
Initial Stamp: 1
Update Successful: true
Updated Value: 200
Updated Stamp: 2

AtomicBoolean উদাহরণ

import java.util.concurrent.atomic.AtomicBoolean;

public class AtomicBooleanExample {
    public static void main(String[] args) {
        AtomicBoolean atomicBoolean = new AtomicBoolean(false);

        System.out.println("Initial Value: " + atomicBoolean.get());

        // মান পরিবর্তন করুন
        atomicBoolean.set(true);
        System.out.println("Updated Value: " + atomicBoolean.get());

        // Compare And Set
        boolean isUpdated = atomicBoolean.compareAndSet(true, false);
        System.out.println("Compare and Set Successful: " + isUpdated);
        System.out.println("Final Value: " + atomicBoolean.get());
    }
}

আউটপুট:

Initial Value: false
Updated Value: true
Compare and Set Successful: true
Final Value: false

কেন java.util.concurrent.atomic প্যাকেজ ব্যবহার করবেন?

  1. থ্রেড-সেইফ:
    • একাধিক থ্রেড থেকে ডেটা অ্যাক্সেস করলেও ডেটা কনসিস্টেন্সি বজায় থাকে।
  2. লক-ফ্রি (Lock-Free):
    • synchronized বা লকের প্রয়োজন নেই, যা পারফরম্যান্স উন্নত করে।
  3. অ্যাপ্লিকেশন পারফরম্যান্স:
    • CPU তে কম ওভারহেড সৃষ্টি করে।
  4. কমপ্লেক্সিটি হ্রাস:
    • সিম্পল মেথড (increment, compareAndSet) দিয়ে কাজ সম্পন্ন করা সহজ।

ব্যবহারের ক্ষেত্রে সীমাবদ্ধতা

  • এই প্যাকেজটি কেবলমাত্র primitive types এবং নির্দিষ্ট কিছু object references এর জন্য উপযোগী।
  • জটিল ডেটা স্ট্রাকচারের জন্য অন্য কনকারেন্সি টুল (যেমন ReentrantLock বা Concurrent Collections) প্রয়োজন।


java.util.concurrent.atomic প্যাকেজটি মাল্টি-থ্রেডেড প্রোগ্রামে ডেটা ম্যানিপুলেশনকে দ্রুত, নিরাপদ, এবং সহজ করে। এটি মাল্টি-থ্রেডেড অ্যাপ্লিকেশনগুলোর জন্য কার্যকর একটি সমাধান।

Content added By

জাভাতে, java.util.concurrent.atomic প্যাকেজে থাকা AtomicInteger, AtomicBoolean, এবং AtomicReference ক্লাসগুলি কনকারেন্ট প্রোগ্রামিংয়ে রেস কন্ডিশন এড়াতে এবং থ্রেড সেফ অপারেশনগুলো করতে ব্যবহৃত হয়। এগুলো সাধারণত অ্যাটমিক অপারেশন (atomic operations) চালায়, যা একই সময়ে একাধিক থ্রেড দ্বারা অ্যাক্সেস করার সময় ডেটার অখণ্ডতা নিশ্চিত করে।

১. AtomicInteger

AtomicInteger একটি অ্যাটমিক ভেরিয়েবল যা শুধুমাত্র পূর্ণসংখ্যার মান ধারণ করে। এটি একাধিক থ্রেড দ্বারা থ্রেড সেফ ভাবে ইঙ্ক্রিমেন্ট, ডিক্রিমেন্ট এবং অন্যান্য গাণিতিক অপারেশন করতে সক্ষম।

ব্যবহার উদাহরণ:

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicIntegerExample {
    public static void main(String[] args) {
        // AtomicInteger তৈরি
        AtomicInteger atomicCounter = new AtomicInteger(0);

        // একাধিক থ্রেডের মাধ্যমে মান ইনক্রিমেন্ট করা
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                atomicCounter.incrementAndGet(); // ইনক্রিমেন্ট এবং ফলস্বরূপ মান ফেরত
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                atomicCounter.incrementAndGet(); // ইনক্রিমেন্ট এবং ফলস্বরূপ মান ফেরত
            }
        });

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // থ্রেডগুলো শেষ হওয়ার পর কনসোলের মাধ্যমে ফলাফল প্রিন্ট করা
        System.out.println("Final Counter Value: " + atomicCounter.get());
    }
}

ব্যাখ্যা:

  • এখানে, AtomicInteger ক্লাসের incrementAndGet() মেথড ব্যবহার করা হয়েছে। এটি ইনক্রিমেন্ট এবং মান ফেরত দেওয়ার অ্যাটমিক অপারেশন করে।
  • একাধিক থ্রেডের মাধ্যমে একসাথে মান আপডেট করা হলেও, এটি নিরাপদ এবং সঠিকভাবে কাজ করে।

২. AtomicBoolean

AtomicBoolean একটি অ্যাটমিক ভ্যালু ধারণকারী বুলিয়ান টাইপের ক্লাস, যা থ্রেড সেফ ফ্ল্যাগ পরিচালনার জন্য ব্যবহার করা হয়।

ব্যবহার উদাহরণ:

import java.util.concurrent.atomic.AtomicBoolean;

public class AtomicBooleanExample {
    public static void main(String[] args) {
        // AtomicBoolean তৈরি
        AtomicBoolean flag = new AtomicBoolean(false);

        // থ্রেড ১
        Thread t1 = new Thread(() -> {
            // যদি flag এর মান false হয় তবে সেটিকে true করা
            if (flag.compareAndSet(false, true)) {
                System.out.println("Thread 1: Flag was false, now set to true");
            }
        });

        // থ্রেড ২
        Thread t2 = new Thread(() -> {
            // যদি flag এর মান false হয় তবে সেটিকে true করা
            if (flag.compareAndSet(false, true)) {
                System.out.println("Thread 2: Flag was false, now set to true");
            }
        });

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

ব্যাখ্যা:

  • এখানে, AtomicBoolean ক্লাসের compareAndSet() মেথড ব্যবহার করা হয়েছে। এটি একটি অ্যাটমিক অপারেশন যা প্রথমে বর্তমান মান চেক করে এবং যদি মানের সাথে মিলে যায়, তাহলে নতুন মান সেট করে।
  • এই কোডে, প্রথম থ্রেড false কে true তে পরিবর্তন করতে সক্ষম হবে, এবং দ্বিতীয় থ্রেড সেটি পরিবর্তন করতে পারবে না যদি প্রথম থ্রেড এটি ইতিমধ্যেই পরিবর্তন করে থাকে।

৩. AtomicReference

AtomicReference একটি জেনেরিক ক্লাস, যা একটি অ্যাটমিকভাবে রেফারেন্স (অবজেক্ট রেফারেন্স) ধারণ করতে ব্যবহৃত হয়। এটি বিভিন্ন থ্রেডের মধ্যে একসাথে অবজেক্ট রেফারেন্সের নিরাপদ আপডেট নিশ্চিত করে।

ব্যবহার উদাহরণ:

import java.util.concurrent.atomic.AtomicReference;

public class AtomicReferenceExample {
    public static void main(String[] args) {
        // AtomicReference তৈরি
        AtomicReference<String> atomicString = new AtomicReference<>("Initial Value");

        // থ্রেড ১
        Thread t1 = new Thread(() -> {
            String current = atomicString.get();
            String updated = current + " Updated by Thread 1";
            atomicString.compareAndSet(current, updated);  // অ্যাটমিকভাবে মান পরিবর্তন
            System.out.println("Thread 1 updated value: " + atomicString.get());
        });

        // থ্রেড ২
        Thread t2 = new Thread(() -> {
            String current = atomicString.get();
            String updated = current + " Updated by Thread 2";
            atomicString.compareAndSet(current, updated);  // অ্যাটমিকভাবে মান পরিবর্তন
            System.out.println("Thread 2 updated value: " + atomicString.get());
        });

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final Value: " + atomicString.get());
    }
}

ব্যাখ্যা:

  • এখানে, AtomicReference ব্যবহার করা হয়েছে যা একটি স্ট্রিং রেফারেন্স ধারণ করে। compareAndSet() মেথড ব্যবহার করে, এটি অ্যাটমিকভাবে রেফারেন্সের মান পরিবর্তন করতে সক্ষম হয়।
  • প্রথম থ্রেড এবং দ্বিতীয় থ্রেড একে অপরের মান আপডেট করতে চেষ্টা করবে, তবে অ্যাটমিক অপারেশন থ্রেড সেফ পরিবর্তন নিশ্চিত করবে।

সারাংশ

  • AtomicInteger: অ্যাটমিকভাবে পূর্ণসংখ্যা মান পরিবর্তন করতে ব্যবহৃত হয় (যেমন: ইঙ্ক্রিমেন্ট, ডিক্রিমেন্ট)।
  • AtomicBoolean: অ্যাটমিকভাবে বুলিয়ান মান পরিবর্তন করতে ব্যবহৃত হয় এবং ফ্ল্যাগ হিসেবে কাজ করে।
  • AtomicReference: জেনেরিক ক্লাস যা একটি অবজেক্ট রেফারেন্স অ্যাটমিকভাবে পরিবর্তন করতে ব্যবহৃত হয়।

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

Content added By

Compare-And-Swap (CAS) হলো একটি লক-ফ্রি কনকারেন্সি কৌশল, যা জাভাতে পারফরম্যান্স উন্নত করার জন্য ব্যবহৃত হয়। এটি atomic operation হিসেবে পরিচিত এবং java.util.concurrent.atomic প্যাকেজে উপলব্ধ।


CAS কীভাবে কাজ করে?

CAS মেকানিজম তিনটি ভ্যালু নিয়ে কাজ করে:

  1. Memory Location (Expected Value): বর্তমান ভ্যালু যা একটি মেমোরি লোকেশনে রয়েছে।
  2. New Value: নতুন ভ্যালু যা আমরা সেট করতে চাই।
  3. Expected Value: বর্তমান ভ্যালু যা আমরা প্রত্যাশা করছি।

কাজের ধাপ:

  • CAS বর্তমান ভ্যালু এবং প্রত্যাশিত ভ্যালু তুলনা করে।
  • যদি তারা মিলে যায়, তবে নতুন ভ্যালু সেট করা হয়।
  • যদি না মিলে যায়, তবে কিছু পরিবর্তন করা হয় না এবং পুনরায় চেষ্টা করা হয়।

CAS এর সুবিধা

  1. লক-ফ্রি মেকানিজম: এটি কোনো লক ছাড়াই কনকারেন্ট ডেটা মডিফিকেশন পরিচালনা করে।
  2. পারফরম্যান্স বৃদ্ধি: লক-ফ্রি অপারেশন হওয়ায় এটি থ্রেড ব্লকিং সমস্যা কমায়।
  3. নির্ভুলতা: একাধিক থ্রেডের মধ্যে ডেটা মডিফিকেশন কনসিস্টেন্ট রাখে।

CAS উদাহরণ: AtomicInteger

import java.util.concurrent.atomic.AtomicInteger;

public class CASExample {
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(5); // শুরুতে ভ্যালু 5

        // বর্তমান ভ্যালু 5 এবং প্রত্যাশিত ভ্যালু 5 হলে 10 সেট করবে
        boolean isUpdated = atomicInteger.compareAndSet(5, 10);

        if (isUpdated) {
            System.out.println("Value updated successfully to: " + atomicInteger.get());
        } else {
            System.out.println("Update failed. Current value: " + atomicInteger.get());
        }

        // পুনরায় চেষ্টা করে নতুন ভ্যালু সেট করার উদাহরণ
        isUpdated = atomicInteger.compareAndSet(5, 15); // প্রত্যাশিত ভ্যালু 5 নয়
        if (!isUpdated) {
            System.out.println("Failed to update as expected value did not match. Current value: " + atomicInteger.get());
        }
    }
}

CAS ব্যবহার করে কাস্টম স্পিনলক উদাহরণ

import java.util.concurrent.atomic.AtomicBoolean;

public class CASSpinLock {
    private final AtomicBoolean lock = new AtomicBoolean(false);

    public void lock() {
        while (!lock.compareAndSet(false, true)) {
            // লক না পাওয়া পর্যন্ত অপেক্ষা
        }
    }

    public void unlock() {
        lock.set(false); // লক মুক্ত করা
    }

    public static void main(String[] args) {
        CASSpinLock spinLock = new CASSpinLock();

        Runnable task = () -> {
            spinLock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + " acquired the lock.");
                Thread.sleep(1000); // কাজ করছে
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                spinLock.unlock();
                System.out.println(Thread.currentThread().getName() + " released the lock.");
            }
        };

        Thread thread1 = new Thread(task, "Thread-1");
        Thread thread2 = new Thread(task, "Thread-2");

        thread1.start();
        thread2.start();
    }
}

CAS ভিত্তিক কনকারেন্সি কন্ট্রোল: উদাহরণ

Counter মেকানিজম

import java.util.concurrent.atomic.AtomicInteger;

class Counter {
    private final AtomicInteger count = new AtomicInteger(0);

    public void increment() {
        int current;
        int newValue;
        do {
            current = count.get(); // বর্তমান মান
            newValue = current + 1; // নতুন মান
        } while (!count.compareAndSet(current, newValue)); // পুনরাবৃত্তি যতক্ষণ না সফল হয়
    }

    public int getCount() {
        return count.get();
    }
}

public class CASCounterExample {
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();

        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        };

        Thread thread1 = new Thread(task);
        Thread thread2 = new Thread(task);

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        System.out.println("Final Counter Value: " + counter.getCount());
    }
}

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

  1. ABA সমস্যা: ভ্যালু পরিবর্তিত হয় এবং পুনরায় সেট হয়, যা CAS মেকানিজমের জন্য বিভ্রান্তি সৃষ্টি করতে পারে। এটি প্রতিরোধ করতে AtomicStampedReference ব্যবহার করা হয়।
  2. ব্যয়বহুল স্পিনলুপ: অনেকবার পুনরায় চেষ্টা করলে স্পিনলুপ বেশি সময় নিতে পারে।
  3. জটিলতা: বড় স্কেলের কনকারেন্সি সমস্যায় CAS কম কার্যকর হতে পারে।

CAS মেকানিজম একটি অত্যন্ত শক্তিশালী এবং কার্যকর কৌশল, যা জাভা কনকারেন্সি উন্নত করে। এটি লক-ফ্রি অপারেশন এবং পারফরম্যান্স বৃদ্ধির জন্য ব্যবহার করা হয়। তবে ABA সমস্যার মত সীমাবদ্ধতাগুলি বিবেচনা করে উন্নত মেকানিজম ব্যবহার করার প্রয়োজন হতে পারে।

Content added By
Promotion

Are you sure to start over?

Loading...