[دوال ] التعامل مع الكلاس Thread في جافا

اذهب الى الأسفل

[دوال ] التعامل مع الكلاس Thread في جافا  Empty [دوال ] التعامل مع الكلاس Thread في جافا

مُساهمة من طرف السنى في الأربعاء أكتوبر 03, 2018 12:37 pm

بسم الله الرحمن الرحيم


مقدمة


يستخدم الكلاس Thread لجعل البرنامج قادر على تنفيذ عدة أوامر مع بعض في وقت واحد, و هو يملك عدة [ندعوك للتسجيل في المنتدى أو التعريف بنفسك لمعاينة هذا الرابط] و خصائص تجعلك قادراً على التحكم بطريقة تنفيذ هذه الأوامر.

كل كائن Thread تقوم بإنشاءه, يتم إعطاءه رقم تعرفة ( id ) و إسم ( name ) خاص فيه, بالتالي يمكن الوصول لكائن الـ Thread من خلال رقم التعرفة أو الإسم الذي أعطي له.

بالإضافة إلى ذلك, يملك كل كائن Thread# رقم بين 1 و 10 يحدد أولية التنفيذ ( Priority ).كائن الـ Thread الذي يملك أعلا Priority يتم تنفيذ أوامره في الأول. لذلك, تلاعب بهذا الرقم فقط في حال كان عندك كائن Thread أهم من غيره.
تلقائياً, أي كائن Thread تقوم بإنشائه, يتم إعطائه Priority تساوي 5 حتى يتم تنفيذ جميع أوامر كائنات الـ Thread بشكل متوازي و عادل.
الكود:

public class Thread
extends Object implements Runnable

ما أن الكلاس Thread يطبق الإنترفيس Runnable, فهذا يؤكد أنهما مصممان لنفس الغرض, و هو جعل البرنامج قادراً على تنفيذ عدة أوامر مع بعض في وقت واحد.


خطوات بناء Thread بواسطة الكلاس Thread

1_نفعل extends للكلاس Thread.
2_نفعل Override للدالة run() لنضع جميع الأوامر التي نريدها أن تتنفذ عند تشغيل كائن الـ Thread.

الكود:

public class MyThread extends Thread {

    @Override
    public void run(){
        // start() هنا تضع الأوامر التي تريد تنفيذها عند إستدعاء الدالة
    }

}



خطوات إنشاء الـ Thread و تشغيله


1_ننشئ كائن من الكلاس الذي يرث من الكلاس Thread.
2_نستدعي الدالة start() لتشغيل كائن الـ Thread.

الكود:

public class Main {

    public static void main(Strigns[] args)){

        MyThread t = new MyThread();
        t.start();

    }

}


إنتبه
في حال قمت بتشغل كائن الـ Thread بواسطة الدالة run() بدل الدالة start(), عندها ستعامل الدالة run() كدالة عادية, أي سيتم إيقاف باقي الأوامر الموجودة في الدالة main() حتى يتم تنفيذ الأوامر الموجودة بداخل الدالة run() ثم العودة للدالة main() لمتابعة تنفيذ باقي الأوامر الموجودة فيها.



الحالات التي يمر بها الـ Thread (Thread States)

عندما تتعامل مع الـ Thread فأنت بذلك تقوم بتغيير حالته, فمرة تنشئه, و مرة تجهزه و تشغله, و قد توقفه عن العمل مدة معينة ثم تعيده للعمل بعد مدة, و عند الإنتهاء يتم مسحه من الذاكرة لتوفير مساحة التخزين.

في الجدول التالي ذكرنا الحالات التي يمر بها الـ Thread.
[ندعوك للتسجيل في المنتدى أو التعريف بنفسك لمعاينة هذا الرابط]


ملاحظة: بعد أن تصبح حالة كائن الـ Thread تساوي TERMINATED يمكن إعطاء رقم التعرفة و إسم الكائن السابق لكائن Thread آخر.

كونستركتورات الكلاس Thread


في الجدول التالي ذكرنا جميع كونستركتورات الكلاس Thread#

1_إنشاء كائن نوعه Thread ليس له إسم محدد.

الكود:
public Thread()

2_إنشاء كائن نوعه Thread مع تحديد إسمه.

الكود:
public Thread(String name)

3_كائن نوعه Thread من كائن نوعه Runnable.

الكود:
public Thread(Runnable target)

4_إنشاء كائن نوعه Thread من كائن نوعه Runnable مع تحديد إسمه

الكود:
public Thread(Runnable target, String name)

5_إنشاء كائن نوعه Thread و يضعه ضمن مجموعة محددة, مع تحديد إسمه
الكود:
public Thread(ThreadGroup group, String name)

باراميترات
_group عبارة عن كائن نوعه ThreadGroup يمثل مجموعة من الـ Threads.
_name عبارة عن إسم يتم إعطاءه لكائن الـ Thread الذي سيتم إنشاءه و وضعه ضمن المجموعة المذكورة.

يرمي الإستثناء SecurityException في حال كان كائن الـ [ندعوك للتسجيل في المنتدى أو التعريف بنفسك لمعاينة هذا الرابط] الحالي لا يملك صلاحية إنشاء كائن Thread جديد بداخل المجموعة المشار إليها.

6_إنشاء كائن نوعه Thread من كائن نوعه Runnable و يضعه ضمن مجموعة محددة
الكود:
public Thread(ThreadGroup group, Runnable target)

باراميترات:


_group عبارة عن كائن نوعه ThreadGroup يمثل مجموعة من الـ Threads.
_target عبارة عن كائن نوعه Runnable يمثل كائن الـ Thread الذي سيتم إنشاءه و وضعه ضمن المجموعة المذكورة.

يرمي الإستثناء SecurityException في حال كان كائن الـ Thread الحالي لا يملك صلاحية إنشاء كائن Thread جديد بداخل المجموعة المشار إليها.

7_كائن نوعه Thread من كائن نوعه Runnable و يضعه ضمن مجموعة محددة, مع تحديد إسمه
الكود:
public Thread(ThreadGroup group, Runnable target, String name)

باراميترات
_group عبارة عن كائن نوعه ThreadGroup يمثل مجموعة من الـ Threads.
_target عبارة عن كائن نوعه Runnable يمثل كائن الـ Thread الذي سيتم إنشاءه و وضعه ضمن المجموعة المذكورة.
_name عبارة عن إسم يتم إعطاءه لكائن الـ Thread الذي سيتم إنشاءه و وضعه ضمن المجموعة المذكورة.

يرمي الإستثناء SecurityException في حال كان كائن الـ Thread الحالي لا يملك صلاحية إنشاء كائن Thread جديد بداخل المجموعة المشار إليها.

8_كائن نوعه Thread من كائن نوعه Runnable و يضعه ضمن مجموعة محددة, مع تحديد إسمه, و تحديد المساحة القصوى التي يمكن أن تحجز له في الذاكرة.
الكود:
public Thread(ThreadGroup group, Runnable target, String name, long stackSize)

باراميترات
_group عبارة عن كائن نوعه ThreadGroup يمثل مجموعة من الـ Threads.
_target عبارة عن كائن نوعه Runnable يمثل كائن الـ Thread الذي سيتم إنشاءه و وضعه ضمن المجموعة المذكورة.
_name عبارة عن إسم يتم إعطاءه لكائن الـ Thread الذي سيتم إنشاءه و وضعه ضمن المجموعة المذكورة.
_stackSize عبارة عن المساحة القصوى التي يمكن أن يحتلها كائن الـ Thread في الذاكرة.

يرمي الإستثناء SecurityException في حال كان كائن الـ Thread الحالي لا يملك صلاحية إنشاء كائن Thread جديد بداخل المجموعة المشار إليها.

دوال الكلاس Thread
يحتوي  الكلاس Thread على الكثير من الدوال التى يمكن استخدامها أمهما على النحو التالى :

1_
الكود:
public void run()
تستخدم لتجهيز الأوامر التي ستنفذ عند تشغيل الـ Thread.
الكلاس الذي يرث من الكلاس Thread يجب أن يفعل لها Override, و يضع بداخلها الأوامر التي يريدها أن تتنفذ عند تشغيل الـ Thread.
ملاحظة: لتشغيل الـ Thread عليك إستدعاء الدالة start() و التي بدورها تقوم باستدعاء الدالة run(), أي تنفذ الأوامر الموجودة فيها.

2_
الكود:
public void start()
تستخدم لتشغيل كائن الـ Thread, أي لتنفيذ الأوامر التي تم وضعها في الدالة run().ترمي الإستثناء IllegalThreadStateException في حال كان كائن الـ Thread شغالا قبل استدعائها.

3_
الكود:
public static void sleep(long milliseconds)
توقف تنفيذ أوامر كائن الـ Thread الذي قام باستدعائها لمدة محددة. بعد إنتهاء هذه المدة يعود للعمل من جديد.
milliseconds هو المدة التي سيتوقف فيها كائن الـ Thread بالـ Milli Seconds.فمثلاً إذا وضعت 1000 مكان هذا الباراميتر, سؤدي ذلك إلى إيقاف كائن الـ Thread عن التنفيذ لثانية واحدة.
ترمي الإستثناء IllegalThreadStateException في حال تم إعطاءها قيمة أصغر من 0.ترمي الإستثناء InterruptedException في حال تم إيقاف كائن الـ Thread في فترة إنتظاره.

4_
الكود:
public static void suspend()
وقف تنفيذ أوامر كائن الـ Thread الذي قام باستدعائها لمدة غير محددة, بحيث لا يمكنه العودة للعمل من جديد إلا إذا قام باستدعاء الدالة resume() بعدها.
ترمي الإستثناء SecurityException في حال كان كائن الـ Thread الحالي لا يملك صلاحية التعديل على كائن الـ Thread المتوقف عن العمل.

5_
الكود:
public static void resume()
تكمل تنفيذ أوامر كائن الـ Thread بعد أن كان قد توقف عن تنفيذها بسبب الدالة suspend().
ترمي الإستثناء SecurityException في حال كان كائن الـ Thread الحالي لا يملك صلاحية التعديل على كائن الـ Thread المتوقف عن العمل.

6_
الكود:
public static void stop()
توقف كائن الـ Thread الذي قام باستدعائها, بحيث لا يمكنه العودة للعمل من جديد.
ترمي الإستثناء SecurityException في حال كان كائن الـ Thread الحالي لا يملك صلاحية التعديل على كائن الـ Thread المتوقف عن العمل.

7_
الكود:
public final void join()
تجعل البرنامج لا يتابع تنفيذ الأوامر الموجودة في الدالة main() حتى يتم تنفيذ جميع الأوامر الموجودة في كائن الـ Thread الذي قام باستدعائها, أي حتى تصبح حالته تساوي TERMINATED.
ملاحظة: لا يهمها إذا كان يوجد أكثر من كائن Thread آخر شغال في نفس الوقت. بمعنى أنه إذا كان هناك كائن Thread آخر شغال فإنه سيستمر في العمل بشكل طبيعي, لكن باقي الأوامر الموجودة في الدالة main() لن يتم تنفيذهم حتى تنفيذ جميع أوامر كائن الـ Thread الذي قام باستدعائها.

ترمي الإستثناء InterruptedException في حال تم إيقاف كائن الـ Thread من قبل أي كائن Thread آخر.


أمثلة شاملة

المثال الأول
المثال التالي عبارة عن برنامج يعرض الوقت الحالي للجهاز.في البداية قمنا بإنشاء كلاس إسمه RealTime يرث من الكلاس Thread.بعدها فعلنا Override للدالة run() لجعلها تطبع الوقت الحالي.ثم قمنا بإنشاء كلاس إسمه Main لتجربة هذا الـ Thread.في الكلاس Main قمنا بإنشاء كائن من الكلاس RealTime ثم قمنا بتشغيله بواسطة الدالة start().

RealTime.java
الكود:
import java.util.Date;        // Date هنا قمنا باستدعاء الكلاس
 
public class RealTime extends Thread {
 
    @Override
    public void run() {
        // true لا ترجع isInterrupted() طالما أن الدالة
        while(!Thread.currentThread().isInterrupted())
        {
            // سيتم طباعة الوقت الحالي
            System.out.printf("Current time: %tr \n", new Date());
 
            // لثانية واحدة Thread بعدها سيتم إيقاف كائن الـ
            try {
                Thread.sleep(1000);
            }
            catch(Exception e) {
                System.out.println(e.getMessage());
            }
        }
    }
 
}

Main.java

الكود:
public class Main {
 
    public static void main(String[] args) {
 
        // t إسمه RealTime هنا قمنا بإنشاء كائن من الكلاس
        RealTime t = new RealTime();
 
        // لعرض الوقت t هنا قمنا بتشغيل الكائن
        t.start();
 
    }
 
}

عند تشغيل البرنامج, سيتم عرض الوقت الحالي كل ثانية كالتالي

Current time: 09:02:15 AM
Current time: 09:02:16 AM
Current time: 09:02:17 AM
Current time: 09:02:18 AM
Current time: 09:02:19 AM
Current time: 09:02:20 AM
Current time: 09:02:21 AM
Current time: 09:02:22 AM
Current time: 09:02:23 AM
Current time: 09:02:24 AM
Current time: 09:02:25 AM
Current time: 09:02:26 AM
Current time: 09:02:27 AM
....

المثال الثاني
المثال التالي عبارة عن برنامج لإختبار قدرة المستخدم في العمليات الحسابية, فهو يقوم بخلق عمليات جمع عشوائية خلال مدة معينة, و إنتظار المستخدم للإجابة عليها, و في الأخير سيتم عرض النتيجة النهائية له.

في البداية قمنا بإنشاء كلاس إسمه ExamTimer يرث من الكلاس Thread.
بعدها فعلنا Override للدالة run() حتى نجعل أي كائن من الكلاس ExamTimer ينتظر مدة 20 ثانية بعد تشغيله, ثم يتوقف مباشرةً عن العمل.

ثم قمنا بإنشاء كلاس إسمه Main, و الذي سيستخدم الكلاس ExamTimer كمؤقت.
في الكلاس Main فعلنا الأشياء التالية:

أنشأنا كائن من الكلاس ExamTimer إسمه et.
قمنا بتشغيل الكائن et بواسطة الدالة start().
قمنا بتعريف المتغيرات num1 و num2 لتخزين الأرقام العشوائية التي سيتم توليدها في البرنامج.
قمنا بتعريف المتغير userAnswer لتخزين العدد الذي سيدخله المستخدم في كل مرة.
قمنا بتعريف المتغيرات operationsCounter, correctAnswersCounter و wrongAnswersCounter كعدادات في البرنامج.
operationsCounter: لتخزين عدد العمليات التي تظهر أمام المستخدم.
correctAnswersCounter: لتخزين عدد إجابات المستخدم الصحيحة.
wrongAnswersCounter: لتخزين عدد إجابات المستخدم الخاطئة.
قمنا بتعريف حلقة while تستمر في توليد أرقام العشوائية, إعداد عمليات جمع و إنتظار المستخدم لإدخال الإجابة بالإعتماد على الدالة isAlive() التي تبقي الحلقة تعيد تنفيذ الأوامر الموجودة فيها طالما أن مدة الإنتظار المحددة للكائن et غير منتهية بعد.

ExamTimer.java

الكود:
public class ExamTimer extends Thread {
 
    @Override
    public void run() {
        // لثانية واحدة Thread بعدها سيتم إيقاف كائن الـ
        try {
            Thread.sleep(20000);
        }
        catch(Exception e) {
            System.out.println(e.getMessage());
        }
    }
 
}


Main.java

الكود:
     
public class Main {
 
    public static void main(String[] args) {
 
        // و الذي سنستخدمه لإدخال بيانات من المستخدم input إسمه Scanner هنا قمنا بإنشاء كائن من الكلاس
        Scanner input = new Scanner(System.in);
 
        // et إسمه ExamTimer هنا قمنا بإنشاء كائن من الكلاس
        ExamTimer et = new ExamTimer();
 
        int num1;                   // سنستخدم هذا المتغير لتخزين أول رقم عشوائي يظهر في عملية الجمع
        int num2;                     سنستخدم هذا المتغير لتخزين ثاني رقم عشوائي يظهر في عملية الجمع
          int userAnswer;               // سنستخدم هذا المتغير لتخزين العدد الذي سيدخله المستخدم للإجابة على عمليأت الجمع
        int operationsCounter = 0;         // سنخزن عدد العمليات الحسابية التي ستظهر عند تشغيل البرنامج فيه
        int correctAnswersCounter = 0;      // سنخزن عدد الإجابات الصحيحة في هذا المتغير
        int wrongAnswersCounter = 0;        // سنخزن عدد الإجابات الخطئ من ي هذا المتغير
 
        // الأمر الذي سيجعله في حالة إنتظار مدة 20 ثانية فقط و بعدها سيتوقف كلياً et هنا قمنا بتشغيل الكائن
        et.start();
 
        System.out.println("---------- Quiz ---------");
 
        // طالما أن مدة العشرين ثانية لم تنقضي بعد سيستمر في تنفيذ الأوامر الموجودة في هذه الحلقة
        while(et.isAlive())
        {
            num1 = (int)(Math.random()*10);             // num1 سيتم تخزين رقم عشوائي بين 1 و 9 في المتغير
            num2 = (int)(Math.random()*10);             // num2 سيتم تخزين رقم عشوائي بين 1 و 9 في المتغير
 
            System.out.print(num1+" + "+num2+" = ");    // num2 و num1 هنا سيطلب من المستخدم معرفة ناتج جمع العددين
            userAnswer = input.nextInt();               // هنا سيتم إنتظار المستخدم لإدخال الجواب
 
            if(userAnswer == num1+num2)                 // إذا كانت إجابته صحيحة, سيتم إضافة عدد الإجابات الصحيحة واحداً
                correctAnswersCounter++;
 
            else                                        // إذا كانت إجابته خاطئة, سيتم إضافة عدد الإجابات الخطأ واحداً
                wrongAnswersCounter++;
 
            operationsCounter++;                        // في الأخير سيتم إضافة عدد عمليات الجمع واحداً
        }
 
        System.out.println("Time end..\n");
 
        // بعد إنتهاء مدة العشرين ثانية سيتم طباعة عدد عمليات الجمع, عدد الأجوبة الصحيحة و عدد الأجوبة الخاطئة
        System.out.println("--------- Result --------");
        System.out.println("Number of operations:      " +operationsCounter);
        System.out.println("Number of correct answers: " +correctAnswersCounter);
        System.out.println("Number of wrong answers:   " +wrongAnswersCounter);
 
    }
 
}

عند تشغيل البرنامج, سنحصل على نتيجة تشبه النتيجة التالية عند التشغيل.الأرقام التي قمنا بتعليمها باللون الأصفر هي التي قمنا بإدخالها عند تجربة البرنامج.

--------- Quiz ---------
0 + 8 = 8
5 + 7 = 11
8 + 8 = 16
6 + 6 = 12
3 + 9 = 12
7 + 4 = 14
9 + 4 = 13
Time end..

--------- Result --------
Number of operations:      7
Number of correct answers: 5
Number of wrong answers:   2
السنى
السنى
........
........

تاريخ التسجيل : 18/02/2011
المساهمات : 223
النقاط : 420
التقيم : 23
الجنس : ذكر

الرجوع الى أعلى الصفحة اذهب الى الأسفل

الرجوع الى أعلى الصفحة

ََ

مواضيع ذات صلة


 
صلاحيات هذا المنتدى:
لاتستطيع الرد على المواضيع في هذا المنتدى