الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

استخدام ال Thread , Runnable , TimerTask

بدأه Mahmoud Kelany في 21 أغسطس 2010 · 8 رد · 3,103 مشاهدة · في JavaSE
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم ورحمه الله وبركاته

اليوم سوف نتكلم عن استخدام الـ Thread , TimerTask , Runnable interface

ازاى دا يحصل

هيكون معانا مثال نستخدم فيه الحاجات دى

الموضوع اننا هنعمل نظام ساعه يتم تحديثها كل ثانيه

فذلك يتم عن طريق ثلاث طرق

وهيا استخدام الـ Thread

او استخدام الـ Runnable interface

او استخدام الـ TimerTask

هيا بنا نتكلم عن كل طريقه بالتفصيل ان شاء الله

لكن هناك جزء بسيط مشترك فى كل حاله

هى انشاء Frame يحتوى على JLable يتم تعديل الوقت عليه كل ثانيه

فقط هذا هو رسم الـ GUI

ناتى الى الجديد فى الموضوع

وهى كيفيه اجلاب الوقت وعرضه وتحديثه

يتم اجلاب الوقت من الـ Calendar Class

وسوف نوضح كيف يتم ذلك

لكن نوضح فقط كيف يتم تحديث الوقت كل مره

وهى انه يتم استخدام احد من الثلاثه اختيارات التى تم ذكرها من قبل

Thread , TimerTask , Runnable

دعنا نشرح كيفيه جلب الوقت

calendar = Calendar.getInstance();

نقوم بانشاء كائن من الكلاس Calendar

طب نجلب الساعات و الدقائق و الثوانى ازاى ؟

نستخدم الداله get(…)

من الكائن calendar

calendar.get(Calendar.HOUR) 
calendar.get(Calendar.MINUTE)
calendar.get(Calendar.SECOND)

لمزيد من المعلومات عن الـ Calendar Class

http://download.oracle.com/javase/1.4.2/docs/api/java/util/Calendar.html

وبعد ذلك نقوم باعاده الكتابه على ال timeLable

لكن هذا يتم تكراره مره واحده

طب تقولى هاعمله فى loop ازاى بقا

هيتكرر ازاى و لا الloop دى هتكون تكرر كام مره ؟

طبعا هنحتاج الى اللجوء الى هدف الدرس

اولا طريقه الـ Thread

    private void timeThread() {
        new Thread() {

            @Override
            public void run() {
                Calendar calendar;
                while (true) {
                    try {
                        calendar = Calendar.getInstance();
                        calendar.setTime(new Date());
                        String time = ("Time (H:M:S) " + calendar.get(Calendar.HOUR) + ":" + calendar.get(Calendar.MINUTE) + ":" + calendar.get(Calendar.SECOND) + "  ");
                        if (calendar.get(Calendar.AM_PM) == 1) {
                            time += "PM";
                        } else {
                            time += "AM";
                        }
                        timeLabel.setText(time);
                        sleep(1000);
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                }
            }
        }.start();
    }

وهى انشاء داله تحتوى على Thread

يحتوى على الاوامر الذى تستخدم فى اعاده ضبط الوقت

كيفيه عمل الخيط

هى عمل

  new  Thread(){

}.start();

ولكن لابد من انشاء الداله المسئوله عن عمليه التشغيل

وهى الداله

run()

ويتم كتابه الكود المسئول عن التحديث بداخلها

كما هو موضح فى الكود مسبقا

وبعد ذلك استدعاء هذه الداله بعد ان يرسم الـ GUI

هكذا

public ClockWithThread() {
        initComponents();
        timeThread();
    }

لمزيد من التفاصيل عن الخيوط

http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Thread.html

ثانيا طريقة الـ Runnable interface

نقوم باعمل implement

هكذا

public class ClockWithRunnable extends javax.swing.JFrame implements Runnable {
}

للـ Runnable interface

وعندها يوجد هناك الداله الخاصه بالتشغيل

اللى هى داله

run ()

فلابد من وجودها

ونقوم ايضا بكتابه الكود الخاص بتحديث الوقت داخلها

 public void run() {
        while (true) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(new Date());
            String time = ("(H:M:S) " + calendar.get(Calendar.HOUR) + ":" + calendar.get(Calendar.MINUTE) + ":" + calendar.get(Calendar.SECOND) + "  ");
            if (calendar.get(Calendar.AM_PM) == 1) {
                time += "PM";
            } else {
                time += "AM";
            }
            timeLabel.setText(time);
        }
    }

وبعد ذلك نقوم باستدعاء عمل الداله run()

لكن لا يمكن استدعائها بالطريقه العاديه كانها داله عاديه

لابد من عمل thread

الذى ياخذ فى البناء الخاص به

Runnable

الذى يكون فى حالتنا هذه هو this

لانه هذه الكلاس تحتوى على

Runnable interface

هكذا

 public ClockWithRunnable() {
        initComponents();
        new Thread(this).start();
    }

لمذيد من المعلومات حول

Runnable interface

http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Runnable.html

الطريقه الثالثه والاخيره

وهى استخدام الـ Timer , TimerTask

نقوم بانشاء كائن من نوع TimerTask

الذى يستوجب ايضا انشاء داله run()

التى يكتب بداخلها نفس الكود الخاص بالتحديث

 private void timerTaskThread() {


        TimerTask timerTask = new TimerTask() {

            public void run() {
                while (true) {
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(new Date());
                    String time = ("(H:M:S) " + calendar.get(Calendar.HOUR) + ":" + calendar.get(Calendar.MINUTE) + ":" + calendar.get(Calendar.SECOND) + "  ");
                    if (calendar.get(Calendar.AM_PM) == 1) {
                        time += "PM";
                    } else {
                        time += "AM";
                    }
                    timeLabel.setText(time);
                }
            }
        };
        Timer timer = new Timer();
        timer.schedule(timerTask, 0, 1000);
    }

وبعد ذلك نقوم بانشاء كائن من النوع Timer

وبعدها نستدعى الداله schedule(…)

على الكائن الذى من النوع Timer

وتاخذ القيم التاليه بالترتيب

timerTask الذى تم تعريفه من قبل

وتاخد مده التاخير فى عمل الكود بالملى ثانيه

وتاخذ اخر قيمه هي مده تكرار هذا الكود كل كام ملى ثانيه ؟؟

وبعد ذلك نستدعى الداله اللتى تحتوى على ال Timer , TimerTask

public ClockWithTimerTask() {
        initComponents();
        timerTaskThread();
    }

لمزيد من المعلومات عن الـ Timer , TimerTask

http://download.oracle.com/javase/1.4.2/docs/api/java/util/TimerTask.html

http://download-llnw.oracle.com/javase/1.5.0/docs/api/javax/swing/Timer.html

الطرق الثلاثه متشابه تشابه كبير

هذا هو الكود الخاص بالثلاث طرق للتحميل

فى ملف واحد عباره عن three Frames

كل طريقه فى Frame منفصل

Clock.zip

اتمنى ان يكون الشرح يكون مفهوم

سلام عليكم

Software Developer
Mahmoudkelany.com


 

#2

عند التعامل مع مكونات ال Swing، فيجب ن تكون كل العمليات التي تقوم بها داخل ال EDT. وما قمت به في الحالات الثلاثة لا يحترم هذه القاعدة.

هناك بديل عن استعمال Thread و Runnable، وهو SwingWorker

Concurrency in Swing

بالنسبة لل Timer، فهناك فئة خاصة بالSwing وهي javax.swing.Timer

How to Use Swing Timers

للمزيد عن ال EDT، هذا شرح الأخ وجدي

herch كتب:

ما فائدة استعمال SwingUtilities.invokeLater(Runnable) وما هو الEDT Event Dispatching Thread [جواب الأخ Wajdy Essam]

في البدايه قبل أن تتعرف على وظيفه الداله SwingUtilities.invokeLater() هناك موضوع مرتبط به وهو Event Dispatched Thread . ففي أي برنامج تقوم بعمله وتنشى كائن من AWT (أو Swing فهي تعتمد على الأولى) وتظهر الكائن (سواء بالداله show أو setVisible أو حتى paint ) فسوف يعمل الحدث الخاص به ولكن لن يعمل في Main Thread بل في ثريد خاص يسمى EDT .

أي أن Event Dispatched Thread هو ثريد خاص للتعامل مع الأحداث وعمليات رسم المكونات drawing and event-handling code سواء Swing أو AWT ، مثلا الدوال paint() و actionPerformed() مباشره سوف تعمل في EDT . -دوال اعاده الرسم ، ودوال التعامل مع الحدث تعمل مباشره في هذا الثريد-

ومكونات Swing هي غير أمنه لحظه التعامل مع الThread (هي Not-Thread Safe) بمعنى أنه يجب عند التعامل مع هذه المكونات أن تعمل في Thread واحد ، وأي داله تحاول أن تغير من قيمه الكائن من Swing يجب أن يعمل في نفس Thread . بعكس AWT .

Once a Swing component has been realized, all code that might affect or depend on the state of that component should be executed in the event-dispatching thread

الأن لكي نقوم بتنفيذ كود داخل الـ EDT ، وفرت sun لنا دالتين في الكلاس SwingUtilities هما :

invokeLater وهي تقوم بوضع الكود الذي تريد أن يعمل في EDT في صف العمليات Event Queue، وترجع مباشره بدون أنتظار تنفيذه ،

invokeAndWait نفس عمل الداله السابقه ولكن تتنظر الى أن يتم تنفيذه ،

هناك طريقه أخرى لتنفيذ الكود في EDT عن طريق Swing Worker أظنه خاص باصدارت جافا 5 وما فوق ، لم أجربه للأسف .

بشكل عام هذه الداله invokeLater تستخدم عندما تريد أن تغير في كائنات Swing من Thread أخر ، فكما في الـ tutorials من sun عند أنشاء مكونات Swing من الداله main ، فيتم انشائها بهذه الداله لأن Main يعمل في Thread منفصل عن EDT .. لكن عند التعامل مع الـ Listener لا توجد حاجه لأنني كما ذكرت في البدايه جميع الـ Listener وpainting و revalidate جميع تلك الداول تعمل في EDT مباشره ،

You only need to use invoke later when you change a component from another thread

على العموم ، بالنسبه لى لم أستخدم هذه الداله ، ربما لأن البرامج التي أقوم بها بسيطه أو لأنه لا توجد حاجه لها في معظم البرامج ، الله أعلم .

روابط مفيده:

Threads and Swing

What exactly is the "Event Dispatch" thread (aka "AWT" Thread)?

>>>>> عودة إلى الأسئلة <<<<<

تم تعديل هذه المشاركة بواسطة herch في 21 أغسطس 2010 في 17:34

1
#3
herch كتب:

عند التعامل مع مكونات ال Swing، فيجب ن تكون كل العمليات التي تقوم بها داخل ال EDT. وما قمت به في الحالات الثلاثة لا يحترم هذه القاعدة.

هناك بديل عن استعمال Thread و Runnable، وهو SwingWorker

Concurrency in Swing

بالنسبة لل Timer، فهناك فئة خاصة بالSwing وهي javax.swing.Timer

How to Use Swing Timers

انا ايه اللى جابنى الـ SE تانى ما انا كنت شغال فى الـ ME

:cry: :cry: :mad: :mad:

اولا اشكرك اخى عصام على المرور والرد الجميل

بس بصراحه انا مش فاهم حاجه :wacko: :wacko: :wacko:

الحاجات دى مش عارفها

معذره على ما حدث

انا دماغى لفت من ساعه ما شوف المقاله لانى مش فاهم حاجه

طب هل اللى انا عملته دا مش صح ؟؟؟؟

يعنى ايه اللى جعله غلط ؟

ام هى احترام للقواعد فقط ام ماذا ؟؟

تم تعديل هذه المشاركة بواسطة Mahmoud Kelany في 21 أغسطس 2010 في 17:59

Software Developer
Mahmoudkelany.com


 

#4
Mahmoud Kelany كتب:

اام هى احترام للقواعد فقط ام ماذا ؟؟

القواعد لا توضع اعتباطا.

العمليات على مكونات ال Swing يجب أن تتم في ال EDT. إذا لم تحترم هذه القاعدة، فيمكن أن يعمل برنامجك، لكن لن تعرف متى سيظهر مشكل في برنامجك، ويمكن أن تتوقف الواجهة عن الإستجابة في أي لحظة، دون أن تعرف ما هو السبب.

إقرأ الروابط الموجودة في ردي، وأيضا في شرح الأخ وجدي .... بعد الفطور wink.gif ممكن تصبح الأمور أوضح ببطن مليء laugh.gif

#5
herch كتب:

القواعد لا توضع اعتباطا.

العمليات على مكونات ال Swing يجب أن تتم في ال EDT. إذا لم تحترم هذه القاعدة، فيمكن أن يعمل برنامجك، لكن لن تعرف متى سيظهر مشكل في برنامجك، ويمكن أن تتوقف الواجهة عن الإستجابة في أي لحظة، دون أن تعرف ما هو السبب.

إقرأ الروابط الموجودة في ردي، وأيضا في شرح الأخ وجدي .... بعد الفطور wink.gif ممكن تصبح الأمور أوضح ببطن مليء laugh.gif

انا فاهم ان القواعد توضع للعب

لكنى لم اكن اعلمها اساسا

اممممم

فعلا عندك حقق ممكن فى فتره من التشغيل تجد البرنامج وقف منك

حاضر

بس كدا هأكل ومش فاهم حاجه

على العموم بجد هاحاول باذن الله

وان لم استطع اكيد هاشوف حل فى انى افهمها

لازم افهمها ان شاء الله :haha: :haha:

اشكرك اخى عصام :clapping: :clapping:

جزاكم الله خيرا

تم تعديل هذه المشاركة بواسطة Mahmoud Kelany في 21 أغسطس 2010 في 18:10

Software Developer
Mahmoudkelany.com


 

#6

مشكور اخي محمود على الموضوع ... :)

في الحقيقة عادة ما اقوم بإضافة ساعة الى اي مشروع من خلال إنشاء JLabel ينفذ الواجهة Runnable و في داخل الكنستراكتر اقوم بتغليف الـ Runnable داخل ثرد بالشكل التالي:

import javax.swing.*;
import java.util.*;
import java.text.*;

public class DigitalClock extends JLabel implements Runnable{

    public DigitalClock() {
        Thread dc = new Thread(this);
        dc.start();
    }

    public void run(){
        try{
            while(true){
                Date theTime = new Date();
                DateFormat df = DateFormat.getTimeInstance(DateFormat.LONG);
                setText(df.format(theTime));
                Thread.sleep(1000);
            }
        }
        catch(InterruptedException ex){

        }
    }
}

لاحظو اني استخدمت الكلاس Date بدلاً من Calender ، فأيهما افضل ؟؟

عموماً بعدها اقوم بإضافة الـ JLabel الى اي تطبيق احتاج فيه الساعة ... كما في الشكل التالي :

import javax.swing.JFrame;
public class MyClock {
    public static void main(String[] args) {
        JFrame frame = new JFrame("My Clock");
        DigitalClock clock = new DigitalClock();
        frame.add(clock);

        frame.setSize(200,100);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(3);
    }
}

لكن الأخ herch أشار الى القوانين التي ذكرها الاخ وجدي ... حاولت ان اقرأ اكثر من مرة و لكن لم استطع ان اصل الى المشكلة المقصودة و التي من اجلها وذكر الاخ وجدي إستخدام EDT ...

اقتباس
العمليات على مكونات ال Swing يجب أن تتم في ال EDT. إذا لم تحترم هذه القاعدة، فيمكن أن يعمل برنامجك، لكن لن تعرف متى سيظهر مشكل في برنامجك، ويمكن أن تتوقف الواجهة عن الإستجابة في أي لحظة، دون أن تعرف ما هو السبب.

???

لا اله الا الله .. محمد رسول الله

(* ربِ اجعلني مقيم الصلاة و من ذريتي ، ربنا و تقبل دعـاء *)

يا حيّ يا قيـوم ... برحمتك استغيث ... اصلح لي شأني كله و لا تكلني الى نفسي طرفة عين

#7

http://download.orac...y/dispatch.html

اقتباس
Swing event handling code runs on a special thread known as the event dispatch thread. Most code that invokes Swing methods also runs on this thread. This is necessary because most Swing object methods are not "thread safe": invoking them from multiple threads risks thread interference or memory consistency errors. Some Swing component methods are labelled "thread safe" in the API specification; these can be safely invoked from any thread. All other Swing component methods must be invoked from the event dispatch thread. Programs that ignore this rule may function correctly most of the time, but are subject to unpredictable errors that are difficult to reproduce.

تم تعديل هذه المشاركة بواسطة herch في 21 أغسطس 2010 في 23:50

#8

تم نقل المشاركات حول التاريخ إلى موضوع مستقل على الرابط التالي

/index.php?showtopic=227277

تحياتي

حزمة المحرك الإصدارة 0.8

أي أحد يجد أني ظلمته فليراسلني

وبإذن الله لو كان له حق سيأخذه

728x90.png

#9
علاء الصالحي كتب:

تم نقل المشاركات حول التاريخ إلى موضوع مستقل على الرابط التالي

/index.php?showtopic=227277

تحياتي

جميل جدا اخ علاء

اهوو هما دول المشرفين :)

جزاك الله خيرا على التنظيم :lol:

Software Developer
Mahmoudkelany.com


 

مواضيع مشابهة