উত্তর:
এর দুটি প্রধান ব্যবহার রয়েছে AtomicInteger
:
পারমাণবিক কাউন্টার হিসাবে ( incrementAndGet()
, ইত্যাদি) যা এক সাথে অনেকগুলি থ্রেড ব্যবহার করতে পারে
একটি আদিম হিসাবে যা অ-ব্লকিং অ্যালগরিদমগুলি বাস্তবায়নের জন্য তুলনা-ও-স্বাপ নির্দেশকে ( compareAndSet()
) সমর্থন করে ।
অনুশীলনে ব্রায়ান গেটজ-এর জাভা কনকুরেন্সি থেকে অ-ব্লক করা এলোমেলো নম্বর জেনারেটরের একটি উদাহরণ এখানে রয়েছে :
public class AtomicPseudoRandom extends PseudoRandom {
private AtomicInteger seed;
AtomicPseudoRandom(int seed) {
this.seed = new AtomicInteger(seed);
}
public int nextInt(int n) {
while (true) {
int s = seed.get();
int nextSeed = calculateNext(s);
if (seed.compareAndSet(s, nextSeed)) {
int remainder = s % n;
return remainder > 0 ? remainder : remainder + n;
}
}
}
...
}
আপনি দেখতে পাচ্ছেন, এটি মূলত প্রায় একইভাবে কাজ incrementAndGet()
করে, তবে calculateNext()
ইনক্রিমেন্টের পরিবর্তে নির্বিচার গণনা ( ) সম্পাদন করে (এবং ফলাফলটি ফিরে আসার আগে প্রক্রিয়া করে)।
read
এবং write that value + 1
অপারেশনগুলির মধ্যে পাল্টা পরিবর্তন করে তবে এটি পুরানো আপডেট ওভাররাইট করার পরিবর্তে ("হারানো আপডেট" সমস্যা এড়ানো) সনাক্ত করা যায়। এটি আসলে একটি বিশেষ ক্ষেত্রে compareAndSet
- যদি পুরানো মান হয় 2
তবে শ্রেণিটি আসলে কল করে compareAndSet(2, 3)
- সুতরাং অন্য থ্রেড যদি এর মধ্যে মানটি সংশোধন করে, বর্ধিত পদ্ধতি কার্যকরভাবে শুরু থেকেই পুনরায় আরম্ভ হয়।
আমি যে পরম সাধারণ উদাহরণটির কথা ভাবতে পারি তা হ'ল বাড়মানবিক ক্রিয়াকলাপ বৃদ্ধি করা।
স্ট্যান্ডার্ড ints সহ:
private volatile int counter;
public int getNextUniqueIndex() {
return counter++; // Not atomic, multiple threads could get the same result
}
অ্যাটমিক ইন্টিজার সহ:
private AtomicInteger counter;
public int getNextUniqueIndex() {
return counter.getAndIncrement();
}
পরবর্তীটি সমস্ত অ্যাক্সেস সিঙ্ক্রোনাইজ করার জন্য অবলম্বন না করে সাধারণ রূপান্তর প্রভাবগুলি (বিশেষত গণনা, বা অনন্য-সূচক) সম্পাদন করার খুব সহজ উপায়।
আরও জটিল সিঙ্ক্রোনাইজেশন-মুক্ত যুক্তিযুক্ত compareAndSet()
এক ধরণের আশাবাদী লকিং হিসাবে ব্যবহার করে নিয়োগ করা যেতে পারে - বর্তমান মান পান, এর উপর ভিত্তি করে গণনা ফলাফল অর্জন করুন, iff মানটি এখনও গণনা করতে ব্যবহৃত ইনপুট হয়, তবে আবার শুরু করুন - তবে গণনা উদাহরণগুলি খুব দরকারী, এবং আমি প্রায়শই AtomicIntegers
গণনা এবং ভিএম-প্রশস্ত অনন্য জেনারেটরগুলির জন্য ব্যবহার করব যদি একাধিক থ্রেড জড়িত থাকে তবে এটির সাথে কাজ করা এত সহজ যে আমি প্রায় এটিকে অপরিহার্যকরণের বিষয়টি বিবেচনা করতে প্লেইন অপরিহার্যতা বিবেচনা করব ints
।
আপনি প্রায়শই সর্বদা একই সিঙ্ক্রোনাইজেশন গ্যারান্টি ints
এবং যথাযথ synchronized
ঘোষণার সাথে অর্জন করতে পারেন , তবে এর সৌন্দর্যটি AtomicInteger
হ'ল থ্রেড-সুরক্ষাটি প্রতিটি পদ্ধতির সম্ভাব্য আন্তঃবিভাজন এবং মনিটরের বিষয়ে চিন্তা করার পরিবর্তে প্রকৃত অবজেক্টটিতেই তৈরি করা হয় every int
মানটি অ্যাক্সেস করতে ঘটে । getAndIncrement()
প্রত্যাবর্তনের সময় i++
এবং স্মরণে রাখার চেয়ে কল করার সময় দুর্ঘটনাবশত থ্রেডসফটি লঙ্ঘন করা (এবং না) মনিটরের সঠিক সেটটি আগেই অর্জন করা hard
আপনি যদি অ্যাটমিকআইন্টিজারের পদ্ধতিগুলি লক্ষ্য করেন তবে আপনি খেয়াল করবেন যে তারা কালিগুলিতে সাধারণ অপারেশনের সাথে মিল রাখে। এই ক্ষেত্রে:
static AtomicInteger i;
// Later, in a thread
int current = i.incrementAndGet();
এটির থ্রেড-নিরাপদ সংস্করণ:
static int i;
// Later, in a thread
int current = ++i;
পদ্ধতি ভালো মানচিত্র:
++i
হয় i.incrementAndGet()
i++
হয় i.getAndIncrement()
--i
হয় i.decrementAndGet()
i--
হয় i.getAndDecrement()
i = x
হয় i.set(x)
x = i
হয়x = i.get()
পাশাপাশি অন্যান্য সুবিধার পদ্ধতি রয়েছে compareAndSet
oraddAndGet
এর প্রাথমিক ব্যবহার AtomicInteger
হ'ল আপনি যখন বহুবিশ্লেষিত প্রসঙ্গে আছেন এবং আপনাকে ব্যবহার না করে কোনও পূর্ণসংখ্যায় থ্রেড নিরাপদ অপারেশন করা দরকার synchronized
। আদিম ধরণের অ্যাসাইনমেন্ট এবং পুনরুদ্ধার int
ইতিমধ্যে পারমাণবিক তবে AtomicInteger
অনেক অপারেশন নিয়ে আসে যা পারমাণবিক নয় int
।
সবচেয়ে সহজ হ'ল getAndXXX
বা xXXAndGet
। উদাহরণস্বরূপ getAndIncrement()
একটি পারমাণবিক সমতুল্য i++
যা পারমাণবিক নয় কারণ এটি আসলে তিনটি অপারেশনের জন্য একটি শর্ট কাট: পুনরুদ্ধার, সংযোজন এবং অ্যাসাইনমেন্ট। compareAndSet
সেমফোরস, লকস, ল্যাচস ইত্যাদি প্রয়োগে খুব কার্যকর useful
ব্যবহার AtomicInteger
দ্রুত এবং আরো একই সিঙ্ক্রোনাইজেশন ব্যবহার করণ চেয়ে পাঠযোগ্য।
একটি সহজ পরীক্ষা:
public synchronized int incrementNotAtomic() {
return notAtomic++;
}
public void performTestNotAtomic() {
final long start = System.currentTimeMillis();
for (int i = 0 ; i < NUM ; i++) {
incrementNotAtomic();
}
System.out.println("Not atomic: "+(System.currentTimeMillis() - start));
}
public void performTestAtomic() {
final long start = System.currentTimeMillis();
for (int i = 0 ; i < NUM ; i++) {
atomic.getAndIncrement();
}
System.out.println("Atomic: "+(System.currentTimeMillis() - start));
}
আমার পিসিতে জাভা ১.6 এর সাথে পারমাণবিক পরীক্ষাটি 3 সেকেন্ডে চলে যখন সমকালীনভাবে প্রায় 5.5 সেকেন্ডে একটি রান করে। এখানে সমস্যা হ'ল সিঙ্ক্রোনাইজ করার অপারেশনটি ( notAtomic++
) সত্যিই স্বল্প। সুতরাং অপারেশনের তুলনায় সিঙ্ক্রোনাইজেশন ব্যয়টি সত্যই গুরুত্বপূর্ণ।
পারমাণবিকতার পাশাপাশি অ্যাটমিক ইন্টিজারকে মান হিসাবে Integer
উদাহরণস্বরূপ পরিবর্তিত সংস্করণ হিসাবে ব্যবহার করা যেতে পারে Map
।
AtomicInteger
মানচিত্র কী হিসাবে ব্যবহার করতে চাই , কারণ এটি ডিফল্ট equals()
বাস্তবায়ন ব্যবহার করে , যা কোনও মানচিত্রে ব্যবহৃত হলে শব্দার্থক হওয়ার প্রত্যাশা আপনি প্রায় করবেন না।
উদাহরণস্বরূপ, আমার কাছে একটি পাঠাগার রয়েছে যা কিছু শ্রেণির উদাহরণ তৈরি করে। এই উদাহরণগুলির প্রত্যেকটির একটি পৃথক পূর্ণসংখ্যার আইডি থাকা আবশ্যক, কারণ এই দৃষ্টান্তগুলি কোনও সার্ভারে প্রেরণ করা আদেশগুলি উপস্থাপন করে এবং প্রতিটি কমান্ডের একটি পৃথক আইডি থাকতে হবে। যেহেতু একাধিক থ্রেড একই সাথে কমান্ড প্রেরণের অনুমতিপ্রাপ্ত তাই আমি এই আইডিগুলি তৈরি করতে একটি অ্যাটমিকআইন্টিজার ব্যবহার করি। একটি বিকল্প পদ্ধতি হ'ল কিছু ধরণের লক এবং নিয়মিত পূর্ণসংখ্যার ব্যবহার করা তবে এটি ধীর এবং কম মার্জিত উভয়ই।
গাবুজো যেমন বলেছিলেন, কখনও কখনও আমি অ্যাটমিক ইন্টিজার ব্যবহার করি যখন আমি কোনও রেফারেন্স দিয়ে কোনও পাস করতে চাই। এটি একটি অন্তর্নির্মিত শ্রেণীর যাতে আর্কিটেকচার-নির্দিষ্ট কোড রয়েছে তাই এটি যে কোনও মিউটেবলইন্টিজারের সাথে আমি দ্রুত কোড আপ করতে পারি তার চেয়ে এটি সহজ এবং সম্ভবত আরও অনুকূল। এটি বলেছিল, এটি ক্লাসের আপত্তিজনক বলে মনে হচ্ছে।
জাভাতে ৮ টি পরমাণু ক্লাস দুটি আকর্ষণীয় ফাংশন সহ বাড়ানো হয়েছে:
উভয়ই পারমাণবিক মানটির আপডেট সম্পাদনা করতে আপডেটফানশন ব্যবহার করছেন। পার্থক্যটি হ'ল প্রথমটি পুরানো মান প্রদান করে এবং দ্বিতীয়টি নতুন মান দেয়। আপডেট ফাংশনটি স্ট্যান্ডার্ডটির চেয়ে আরও জটিল "তুলনা এবং সেট" অপারেশন করতে প্রয়োগ করা যেতে পারে। উদাহরণস্বরূপ এটি পরীক্ষা করতে পারে যে পারমাণবিক কাউন্টার শূন্যের নীচে যায় না, সাধারণত এটির জন্য সিঙ্ক্রোনাইজেশন প্রয়োজন হয় এবং এখানে কোডটি লক-ফ্রি রয়েছে:
public class Counter {
private final AtomicInteger number;
public Counter(int number) {
this.number = new AtomicInteger(number);
}
/** @return true if still can decrease */
public boolean dec() {
// updateAndGet(fn) executed atomically:
return number.updateAndGet(n -> (n > 0) ? n - 1 : n) > 0;
}
}
কোডটি জাভা পারমাণবিক উদাহরণ থেকে নেওয়া হয়েছে ।
আমি যখন সাধারণত একাধিক থ্রেড থেকে অ্যাক্সেস বা তৈরি করা যায় এমন বস্তুকে আইডি দেওয়ার দরকার হয় তখন আমি সাধারণত অ্যাটমিকিন্টেজার ব্যবহার করি এবং আমি সাধারণত ক্লাসে স্থির বৈশিষ্ট্য হিসাবে এটি ব্যবহার করি যা আমি অবজেক্টগুলির নির্মাতায় প্রবেশ করি।
আপনি পারমাণবিক পূর্ণসংখ্যার বা লম্বায় তুলনাঅ্যান্ডসাপ (সিএএস) ব্যবহার করে অ-ব্লকিং লকগুলি প্রয়োগ করতে পারেন। "Tl2" সফ্টওয়্যার লেনদেনগত মেমরি কাগজ এই বর্ণনা
আমরা প্রতিটি লেনদেনের মেমরির অবস্থানের সাথে একটি বিশেষ সংস্করণযুক্ত রাইটিং-লক যুক্ত করি। এর সহজতম ফর্মটিতে, সংস্করণযুক্ত রাইটিং-লকটি একটি একক শব্দ স্পিনলক যা লকটি অর্জন করার জন্য একটি সিএএস অপারেশন এবং এটি প্রকাশের জন্য একটি স্টোর ব্যবহার করে। যেহেতু লকটি নেওয়া হয়েছে তা বোঝাতে কেবল একটি মাত্র বিট প্রয়োজন, তাই আমরা বাক্সটি বাকী বাক্যটি একটি সংস্করণ নম্বর ধরে ব্যবহার করি।
এটি যা বর্ণনা করছে তা প্রথমে পরমাণু পূর্ণসংখ্যা পড়া। এটিকে উপেক্ষা করা লক-বিটে এবং সংস্করণ নম্বরটিতে ভাগ করুন। সিএএস-এর প্রচেষ্টা এটি লক-বিট সেট এবং পরবর্তী সংস্করণ নম্বরটিতে বর্তমান সংস্করণ নম্বর সহ লক-বিট সাফ হয়ে যায় বলে লিখুন। আপনি সফল হওয়া অবধি লুপ করুন এবং আপনার থ্রেড যা লকটির মালিক। লক-বিট সাফ হয়ে বর্তমান সংস্করণ নম্বর সেট করে আনলক করুন। কাগজটি লকগুলিতে সংস্করণ নম্বরগুলি ব্যবহার করে বর্ণনা করে যে থ্রেডগুলি লেখার সময় একটি নিয়মিত পঠনের সেট থাকে।
এই নিবন্ধটি বর্ণনা করে যে প্রসেসরের তুলনা করার জন্য হার্ডওয়্যার সমর্থন রয়েছে এবং অপারেশনকে খুব দক্ষ করে তোলে। এটি আরও দাবি করে:
পারমাণবিক ভেরিয়েবলগুলি ব্যবহার করে অ-ব্লকিং সিএএস-ভিত্তিক কাউন্টারগুলিতে কম থেকে মাঝারি মতবিরোধে লক-ভিত্তিক কাউন্টারগুলির চেয়ে ভাল পারফরম্যান্স রয়েছে
মূলটি হ'ল তারা নিরাপদে নিরাপদে একযোগে অ্যাক্সেস এবং পরিবর্তনের অনুমতি দেয়। এগুলি সাধারণত একটি বহুবিবাহিত পরিবেশে কাউন্টার হিসাবে ব্যবহৃত হয় - তাদের পরিচয়ের আগে এটি ব্যবহারকারীর লিখিত শ্রেণি হতে হবে যা সিঙ্ক্রোনাইজড ব্লকে বিভিন্ন পদ্ধতি মুছে ফেলে।
আমি ডাইনিং দার্শনিকের সমস্যা সমাধানের জন্য অ্যাটমিকআইন্টিজার ব্যবহার করেছি।
আমার সমাধানে, অ্যাটমিকআইন্টিজার উদাহরণগুলি কাঁটাচামচকে উপস্থাপন করতে ব্যবহৃত হয়েছিল, দার্শনিকের জন্য দুটি প্রয়োজন needed প্রতিটি দার্শনিক একটি পূর্ণসংখ্যা হিসাবে চিহ্নিত করা হয়, 1 থেকে 5 পর্যন্ত। যখন একটি দার্শনিক দ্বারা একটি কাঁটাচামচ ব্যবহার করা হয়, তখন অ্যাটমিক ইন্টিজার দার্শনিকের মান ধরে রাখে, 1 থেকে 5 পর্যন্ত, অন্যথায় কাঁটাটি ব্যবহার করা হচ্ছে না সুতরাং অ্যাটমিক ইন্টিজারের মান -1 হয় ।
পরমাণুবিজ্ঞানী তারপরে একটি পরমাণু অপারেশনে একটি কাঁটাচামচ বিনামূল্যে, মান == - 1 আছে কিনা তা পরীক্ষা করতে এবং এটি ফর্কটির মালিককে বিনামূল্যে নির্ধারণের জন্য সেট করে। নীচে কোড দেখুন।
AtomicInteger fork0 = neededForks[0];//neededForks is an array that holds the forks needed per Philosopher
AtomicInteger fork1 = neededForks[1];
while(true){
if (Hungry) {
//if fork is free (==-1) then grab it by denoting who took it
if (!fork0.compareAndSet(-1, p) || !fork1.compareAndSet(-1, p)) {
//at least one fork was not succesfully grabbed, release both and try again later
fork0.compareAndSet(p, -1);
fork1.compareAndSet(p, -1);
try {
synchronized (lock) {//sleep and get notified later when a philosopher puts down one fork
lock.wait();//try again later, goes back up the loop
}
} catch (InterruptedException e) {}
} else {
//sucessfully grabbed both forks
transition(fork_l_free_and_fork_r_free);
}
}
}
কারণ তুলনাআন্ডসেট পদ্ধতিটি ব্লক করে না, এটি থ্রুপুট বৃদ্ধি করতে হবে, আরও কাজ করা উচিত। যেমন আপনি জানেন যে ডাইনিং ফিলোসফার্স সমস্যা ব্যবহার করা হয় যখন সংস্থাগুলিতে অ্যাক্সেস পাওয়া নিয়ন্ত্রণ করা হয়, যেমন কাঁটাচামচ প্রয়োজন, যেমন প্রক্রিয়াটির কাজ চালিয়ে যাওয়ার জন্য সংস্থান প্রয়োজন।
তুলনাআন্ডসেট () ফাংশনের জন্য সাধারণ উদাহরণ:
import java.util.concurrent.atomic.AtomicInteger;
public class GFG {
public static void main(String args[])
{
// Initially value as 0
AtomicInteger val = new AtomicInteger(0);
// Prints the updated value
System.out.println("Previous value: "
+ val);
// Checks if previous value was 0
// and then updates it
boolean res = val.compareAndSet(0, 6);
// Checks if the value was updated.
if (res)
System.out.println("The value was"
+ " updated and it is "
+ val);
else
System.out.println("The value was "
+ "not updated");
}
}
মুদ্রিতটি হ'ল: পূর্ববর্তী মান: 0 মানটি আপডেট করা হয়েছিল এবং এটি 6 অন্য একটি সাধারণ উদাহরণ:
import java.util.concurrent.atomic.AtomicInteger;
public class GFG {
public static void main(String args[])
{
// Initially value as 0
AtomicInteger val
= new AtomicInteger(0);
// Prints the updated value
System.out.println("Previous value: "
+ val);
// Checks if previous value was 0
// and then updates it
boolean res = val.compareAndSet(10, 6);
// Checks if the value was updated.
if (res)
System.out.println("The value was"
+ " updated and it is "
+ val);
else
System.out.println("The value was "
+ "not updated");
}
}
মুদ্রিতটি হ'ল: পূর্ববর্তী মান: 0 মান আপডেট করা হয়নি