তারা অভ্যন্তরীণভাবে কীভাবে কাজ করে সে সম্পর্কে আপনি বিশেষত জিজ্ঞাসা করছেন , সুতরাং আপনি এখানে আছেন:
কোনও সিঙ্ক্রোনাইজেশন নেই
private int counter;
public int getNextUniqueIndex() {
return counter++;
}
এটি মূলত মেমরি থেকে মান পড়ে, এটিকে বাড়িয়ে দেয় এবং মেমরিতে ফিরে দেয়। এটি একক থ্রেডে কাজ করে তবে আজকাল, মাল্টি-কোর, মাল্টি-সিপিইউ, মাল্টি-লেভেল ক্যাশের যুগে এটি সঠিকভাবে কাজ করবে না। সবার আগে এটি জাতি শর্তের পরিচয় দেয় (বেশ কয়েকটি থ্রেড একই সাথে মানটি পড়তে পারে), তবে দৃশ্যমানতার সমস্যাও রয়েছে। মানটি কেবলমাত্র " স্থানীয় " সিপিইউ মেমোরিতে (কিছু ক্যাশে) সঞ্চিত থাকতে পারে এবং অন্যান্য সিপিইউ / কোরগুলির জন্য দৃশ্যমান নাও হতে পারে (এবং এইভাবে - থ্রেড)। এ কারণেই অনেকে একটি থ্রেডে ভেরিয়েবলের স্থানীয় অনুলিপি উল্লেখ করেন । এটি খুব অনিরাপদ। এই জনপ্রিয় তবে ভাঙা থ্রেড-স্টপিং কোডটি বিবেচনা করুন:
private boolean stopped;
public void run() {
while(!stopped) {
//do some work
}
}
public void pleaseStop() {
stopped = true;
}
যোগ volatile
করার জন্য stopped
পরিবর্তনশীল এবং এটি কাজ করে জরিমানা - অন্য কোন থ্রেড মডিফাই যদি stopped
মাধ্যমে পরিবর্তনশীল pleaseStop()
পদ্ধতি, আপনি যে পরিবর্তন অবিলম্বে দেখতে থ্রেড এর কাজ গ্যারান্টী আছে while(!stopped)
লুপ। : BTW এই একটি ভালো উপায়, হয় একটি থ্রেড সাময়িক বিরতি দেখতে নয় কিভাবে একটি থ্রেড চিরকাল কোনো ব্যবহার না করে চলমান থামাতে এবং একটি নির্দিষ্ট জাভা থ্রেড বন্ধ ।
AtomicInteger
private AtomicInteger counter = new AtomicInteger();
public int getNextUniqueIndex() {
return counter.getAndIncrement();
}
AtomicInteger
বর্গ ব্যবহারসমূহ সি এ এস ( তুলনা-এবং-swap 'র ) নিম্নস্তরের CPU- র অপারেশন (কোন সিঙ্ক্রোনাইজেশন প্রয়োজন!) তারা আপনাকে একটি নির্দিষ্ট পরিবর্তনশীল পরিবর্তন করতে শুধুমাত্র যদি বর্তমান মূল্য অন্য কিছু সমান (এবং সফলভাবে ফিরিয়ে দেওয়া হয়) অনুমতি দেয়। সুতরাং আপনি যখন getAndIncrement()
এটি কার্যকর করেন তখন আসলে একটি লুপে চালিত হয় (সরলীকৃত বাস্তব বাস্তবায়ন):
int current;
do {
current = get();
} while(!compareAndSet(current, current + 1));
সুতরাং মূলত: পড়ুন; বর্ধিত মান সংরক্ষণ করার চেষ্টা করুন; সফল না হলে (মানটি আর সমান হয় না current
), পড়ুন এবং আবার চেষ্টা করুন। compareAndSet()
নেটিভ কোড (সমাবেশ) বাস্তবায়িত হয়।
volatile
সিঙ্ক্রোনাইজেশন ছাড়াই
private volatile int counter;
public int getNextUniqueIndex() {
return counter++;
}
এই কোডটি সঠিক নয়। এটি দৃশ্যমানতার সমস্যাটি সমাধান করে (এটি volatile
নিশ্চিত করে যে অন্যান্য থ্রেডগুলি এর পরিবর্তিত পরিবর্তন দেখতে পারে counter
) তবে এখনও রেসের শর্ত রয়েছে। এটি একাধিকবার ব্যাখ্যা করা হয়েছে: প্রাক / উত্তর-বর্ধন পরমাণু নয়।
এর একমাত্র পার্শ্ব প্রতিক্রিয়া volatile
হ'ল " ফ্লাশিং " ক্যাশে যাতে অন্যান্য সমস্ত পক্ষই তথ্যের সতেজ সংস্করণটি দেখতে পায়। বেশিরভাগ পরিস্থিতিতে এটি অত্যন্ত কঠোর; এজন্যই volatile
ডিফল্ট নয়।
volatile
সিঙ্ক্রোনাইজেশন ছাড়াই (2)
volatile int i = 0;
void incIBy5() {
i += 5;
}
উপরের মতো একই সমস্যা, তবে আরও খারাপ কারণ এটিও i
নয় private
। দৌড়ের অবস্থা এখনও বিদ্যমান। কেন এটি একটি সমস্যা? যদি, বলুন, দুটি থ্রেড একই সাথে এই কোডটি চালায় তবে আউটপুট হতে পারে + 5
বা + 10
। যাইহোক, আপনি পরিবর্তনটি দেখতে গ্যারান্টিযুক্ত।
একাধিক স্বতন্ত্র synchronized
void incIBy5() {
int temp;
synchronized(i) { temp = i }
synchronized(i) { i = temp + 5 }
}
আশ্চর্য, এই কোডটিও ভুল। আসলে, এটি সম্পূর্ণ ভুল। প্রথমে আপনি সিঙ্ক্রোনাইজ করছেন i
যা পরিবর্তন হতে চলেছে (তদ্ব্যতীত, i
একটি আদিম, তাই আমি অনুমান করি আপনি Integer
অটোবক্সিংয়ের মাধ্যমে তৈরি একটি অস্থায়ী সাথে সিঙ্ক্রোনাইজ করছেন ...) সম্পূর্ণ ত্রুটিযুক্ত। আপনি আরও লিখতে পারেন:
synchronized(new Object()) {
//thread-safe, SRSLy?
}
কোনও দুটি থ্রেড একই লক দিয়ে একই synchronized
ব্লকে প্রবেশ করতে পারে না । এই ক্ষেত্রে (এবং একইভাবে আপনার কোডে) লক অবজেক্ট প্রতিটি মৃত্যুদন্ড কার্যকর হওয়ার পরে পরিবর্তিত হয়, তাই কার্যকরভাবে কোনও প্রভাব পড়ে না।synchronized
এমনকি যদি আপনি this
সিঙ্ক্রোনাইজেশনের জন্য একটি চূড়ান্ত পরিবর্তনশীল (বা ) ব্যবহার করেন তবে কোডটি এখনও ভুল। দুটি থ্রেড প্রথমে একযোগে পড়তে i
পারে temp
(স্থানীয়ভাবে একই মান থাকা temp
), তারপরে প্রথমটি একটি নতুন মান নির্ধারণ করে i
(বলুন, 1 থেকে 6 পর্যন্ত) এবং অন্যটি একই জিনিসটি করে (1 থেকে 6 পর্যন্ত)।
সিঙ্ক্রোনাইজেশন অবশ্যই পাঠ্য থেকে শুরু করে একটি মান নির্ধারণ পর্যন্ত বিস্তৃত। আপনার প্রথম সিঙ্ক্রোনাইজেশনের কোনও প্রভাব নেই (একটি int
পড়াটি পরমাণু হয়) এবং দ্বিতীয়টিও। আমার মতে, এগুলি সঠিক ফর্মগুলি:
void synchronized incIBy5() {
i += 5
}
void incIBy5() {
synchronized(this) {
i += 5
}
}
void incIBy5() {
synchronized(this) {
int temp = i;
i = temp + 5;
}
}