اليوم سنتعرف على AtomicInteger
في جافا. تُنفذ العمليات الذرية في وحدة مفردة من المهمة دون تداخل من العمليات الأخرى. العمليات الذرية ضرورية في البيئة متعددة الخيوط لتجنب عدم اتساق البيانات.
AtomicInteger
دعنا نقوم بإنشاء برنامج متعدد الخيوط بسيط حيث يقوم كل خيط بزيادة متغير الـ
count
المشترك 4 مرات. لذلك إذا كان هناك خيطان، بعد انتهائهما يجب أن يكون قيمة count
8. JavaAtomic.java
package com.journaldev.concurrency;
public class JavaAtomic {
public static void main(String[] args) throws InterruptedException {
ProcessingThread pt = new ProcessingThread();
Thread t1 = new Thread(pt, "t1");
t1.start();
Thread t2 = new Thread(pt, "t2");
t2.start();
t1.join();
t2.join();
System.out.println("Processing count=" + pt.getCount());
}
}
class ProcessingThread implements Runnable {
private int count;
@Override
public void run() {
for (int i = 1; i < 5; i++) {
processSomething(i);
count++;
}
}
public int getCount() {
return this.count;
}
private void processSomething(int i) {
// تجهيز بعض المهمات
try {
Thread.sleep(i * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
إذا قمت بتشغيل البرنامج أعلاه، ستلاحظ أن قيمة count
تتراوح بين 5 و 6 و 7 و 8. السبب في ذلك هو لأن count++ ليست عملية ذرية. لذلك بحلول الوقت الذي يقرأ فيه أحد الخيوط قيمته ويزيد منها بواحد، قرأ الخيط الآخر القيمة القديمة مما يؤدي إلى نتيجة خاطئة. لحل هذه المشكلة، يجب أن نتأكد من أن عملية الزيادة في count هي ذرية، يمكننا القيام بذلك باستخدام التزامن ولكن جافا 5 java.util.concurrent.atomic
توفر فئات تغليف للأعداد الصحيحة والطويلة يمكن استخدامها لتحقيق هذه العملية الذرية دون استخدام التزامن.
مثال Java AtomicInteger
إليك البرنامج المحدث الذي سيقوم دائمًا بإخراج قيمة العداد كـ 8 لأن طريقة incrementAndGet()
في AtomicInteger
تزيد القيمة الحالية بشكل ذري.
package com.journaldev.concurrency;
import java.util.concurrent.atomic.AtomicInteger;
public class JavaAtomic {
public static void main(String[] args) throws InterruptedException {
ProcessingThread pt = new ProcessingThread();
Thread t1 = new Thread(pt, "t1");
t1.start();
Thread t2 = new Thread(pt, "t2");
t2.start();
t1.join();
t2.join();
System.out.println("Processing count=" + pt.getCount());
}
}
class ProcessingThread implements Runnable {
private AtomicInteger count = new AtomicInteger();
@Override
public void run() {
for (int i = 1; i < 5; i++) {
processSomething(i);
count.incrementAndGet();
}
}
public int getCount() {
return this.count.get();
}
private void processSomething(int i) {
// يتم معالجة بعض المهام
try {
Thread.sleep(i * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
من فوائد استخدام فئات التوازي للعمليات الذرية هو أننا لا نحتاج إلى القلق بشأن التزامن. يؤدي هذا إلى تحسين قراءة الشفرة وتقليل فرص الأخطاء. كما يفترض أن تكون فئات التوازي للعمليات الذرية أكثر كفاءة من التزامن الذي ينطوي على قفل الموارد.
Source:
https://www.digitalocean.com/community/tutorials/atomicinteger-java