المتغيرات الذرية: تحديثات دون أقفال
استخدم AtomicInteger وAtomicLong وAtomicReference لإنشاء عدادات آمنة للخيوط دون أقفال
المتغيرات الذرية: تحديثات دون أقفال درس مجاني في Java Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Java Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Java Academy 4 دروس في المجموع.
مشكلة العمليات غير الذرية
الزيادة البسيطة count++ ليست آمنة للخيوط — فهي تتكون من ثلاث عمليات: قراءة وإضافة وكتابة. ويمكن للخيوط المتزامنة أن تتداخل في تنفيذها، مما يؤدي إلى فقدان التحديثات. وتحل المتغيرات الذرية هذه المشكلة دون أقفال.
// UNSAFE:
int count = 0;
// Thread A reads count=0, Thread B reads count=0
// Both write 1 — second update lost!
count++; // NOT thread-safe
// SAFE:
import java.util.concurrent.atomic.*;
AtomicInteger atomicCount = new AtomicInteger(0);
atomicCount.incrementAndGet(); // atomic, lock-freeأساسيات AtomicInteger
يوفر AtomicInteger عمليات على الأعداد الصحيحة مضمونة الذرية باستخدام تعليمات المقارنة والتبديل (CAS) في وحدة المعالجة المركزية — ولا يحتاج إلى أقفال.
AtomicInteger counter = new AtomicInteger(0);
counter.set(10); // set to 10
System.out.println(counter.get()); // 10
int prev = counter.getAndIncrement(); // returns 10, sets to 11
int curr = counter.incrementAndGet(); // sets to 12, returns 12
counter.addAndGet(5); // adds 5, returns 17
counter.decrementAndGet(); // subtracts 1, returns 16compareAndSet: عملية CAS
يحدّث compareAndSet(expected, update) القيمة ذريًا فقط إذا كانت تساوي حاليًا القيمة المتوقعة. ويُرجع true عند النجاح. وتشكل هذه العملية أساس جميع الخوارزميات الخالية من الأقفال.
AtomicInteger ai = new AtomicInteger(5);
boolean updated = ai.compareAndSet(5, 10); // current==5? set to 10
System.out.println(updated); // true
System.out.println(ai.get()); // 10
boolean failed = ai.compareAndSet(5, 20); // current==10, not 5 → fails
System.out.println(failed); // false
System.out.println(ai.get()); // still 10AtomicLong للعدادات
يمثل AtomicLong النظير ذي 64 بت. ويُستخدم عادةً لمولدات التسلسل وعدادات مرات الوصول:
AtomicLong seq = new AtomicLong(0);
// Thread-safe sequence generator:
long nextId() {
return seq.incrementAndGet();
}
System.out.println(nextId()); // 1
System.out.println(nextId()); // 2
System.out.println(nextId()); // 3AtomicBoolean
علامة منطقية آمنة للخيوط. تُستخدم عادةً للتهيئة لمرة واحدة أو إشارات إيقاف التشغيل:
AtomicBoolean initialized = new AtomicBoolean(false);
void initOnce() {
// compareAndSet: only first caller succeeds
if (initialized.compareAndSet(false, true)) {
System.out.println("Initializing...");
// perform expensive init
} else {
System.out.println("Already initialized");
}
}AtomicReference
يوفر AtomicReference<V> تحديثات ذرية لمرجع كائن. ويُستخدم لتنفيذ هياكل بيانات خالية من الأقفال:
import java.util.concurrent.atomic.*;
record Config(String host, int port) {}
AtomicReference<Config> configRef =
new AtomicReference<>(new Config("localhost", 8080));
// Hot-swap the configuration atomically:
Config oldConfig = configRef.get();
Config newConfig = new Config("prod.example.com", 443);
boolean swapped = configRef.compareAndSet(oldConfig, newConfig);
System.out.println(swapped); // true
System.out.println(configRef.get()); // Config[host=prod.example.com, port=443]updateAndGet / getAndUpdate
طبّق دالة ذريًا باستخدام حلقة إعادة محاولة CAS داخليًا:
AtomicInteger value = new AtomicInteger(10);
// Apply function atomically: square the value
int newVal = value.updateAndGet(x -> x * x);
System.out.println(newVal); // 100
// Get old, then apply:
int old = value.getAndUpdate(x -> x + 1);
System.out.println(old); // 100
System.out.println(value.get()); // 101accumulateAndGet
ادمج القيمة الحالية مع قيمة معطاة باستخدام دالة:
AtomicInteger max = new AtomicInteger(0);
// Keep running maximum:
max.accumulateAndGet(42, Math::max); // max(0, 42) = 42
max.accumulateAndGet(15, Math::max); // max(42, 15) = 42
max.accumulateAndGet(99, Math::max); // max(42, 99) = 99
System.out.println(max.get()); // 99LongAdder لعدادات التنازع العالي
عند ارتفاع تنازع الخيوط، قد تؤثر إعادة محاولات CAS في AtomicLong سلبًا على الأداء. ويستخدم LongAdder خلايا متعددة لتقليل التنازع:
import java.util.concurrent.atomic.*;
LongAdder adder = new LongAdder();
// Multiple threads can call add() with minimal contention:
adder.increment();
adder.add(5);
adder.increment();
System.out.println(adder.sum()); // 7
// Note: sum() is NOT atomic with add() — use only when no concurrent addsالمصفوفات الذرية
يوفر AtomicIntegerArray / AtomicLongArray عمليات ذرية على عناصر المصفوفة الفردية:
AtomicIntegerArray arr = new AtomicIntegerArray(5);
arr.set(0, 10);
arr.incrementAndGet(0);
arr.compareAndSet(2, 0, 42); // index 2: if 0, set 42
System.out.println(arr.get(0)); // 11
System.out.println(arr.get(2)); // 42متى تستخدم المتغيرات الذرية بدلًا من الأقفال
استخدم المتغيرات الذرية عندما:
- تُحدّث متغيرًا واحدًا (عدادات أو علامات أو مراجع)
- يكون التنازع منخفضًا
- يكون الأداء الخالي من الأقفال مهمًا
استخدم الأقفال عندما:
- يجب تحديث عدة متغيرات ذريًا
- تحتاج إلى منطق شرطي معقد
- يكون التنازع مرتفعًا جدًا (إذ تؤثر إعادة محاولات CAS سلبًا على الأداء)
اختبار سريع
ما الضمان الذي يوفره compareAndSet(expected, update)؟
مراجعة: المتغيرات الذرية
أهم النقاط:
- تستخدم الأنواع الذرية تعليمات CAS في وحدة المعالجة المركزية — وهي خالية من الأقفال وآمنة للخيوط
- توفر AtomicInteger/Long/Boolean/Reference ذرية العمليات على متغير واحد
- تشكل compareAndSet أساس الخوارزميات الخالية من الأقفال
- تُستخدم updateAndGet/accumulateAndGet للتحديثات الوظيفية
- يُستخدم LongAdder في سيناريوهات العدادات ذات التنازع العالي
الأسئلة الشائعة
هل درس «المتغيرات الذرية: تحديثات دون أقفال» مجاني؟
نعم — نص درس «المتغيرات الذرية: تحديثات دون أقفال» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Java Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Java Academy 4 دروس في المجموع.
ماذا ستتعلم في «المتغيرات الذرية: تحديثات دون أقفال»؟
استخدم AtomicInteger وAtomicLong وAtomicReference لإنشاء عدادات آمنة للخيوط دون أقفال تتمرن على Java Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Java Academy؟
لا تُشترط خبرة سابقة. Java Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «المتغيرات الذرية: تحديثات دون أقفال»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Java Academy هذا؟
نعم. كل درس في Java Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- ReentrantLock مقابل synchronized
- ReadWriteLock لسيناريوهات القارئ والكاتب
- المتغيرات الذرية: تحديثات دون أقفال
- StampedLock والقراءات المتفائلة