CodeGym /Kurslar /JAVA 25 SELF /EDT axını və UI-də uzunmüddətli əməliyyatlar

EDT axını və UI-də uzunmüddətli əməliyyatlar

JAVA 25 SELF
Səviyyə , Dərs
Mövcuddur

1. EDT (Event Dispatch Thread) nədir

Java-da qrafik tətbiqlərdə — istər Swing, istərsə də JavaFX — istifadəçinin bütün hərəkətləri (kliklər, düymələr), eləcə də pəncərələrin yenidən çəkilməsi EDT (Event Dispatch Thread, hadisələrin işlənməsi axını) adlı xüsusi axında emal olunur.

Nəyə görə lazımdır? Java-da UI komponentləri axın‑təhlükəsiz deyil. Yarış şəraitini və artefaktları önləmək üçün interfeysə edilən bütün dəyişikliklər yalnız bir yerdə — EDT-də icra olunur. Bu, tək kassalı kassaya bənzəyir: eyni qəbzlə eyni anda bir neçə nəfər məşğul ola bilməz.

Swing-də EDT hadisə emalçılarını və komponentlərin yenidən çəkilməsini işə salır (məsələn, actionPerformed). JavaFX-də analoqu — JavaFX Application Thread — burada UI yeniləmələri və setOnAction kimi emalçılar icra olunur.

2. UI-də “uzun əməliyyatlar” problemi

EDT-də uzun bir əməliyyat işə salınsa nə baş verəcək?

İstifadəçi düyməni basanda emalçı (məsələn, actionPerformed və ya setOnAction) EDT-də icra olunur. Əgər daxilində ağır tapşırıq (böyük faylın oxunması, şəbəkə sorğusu, mürəkkəb hesablamalar) işə salırsınızsa, bütün UI “donur”:

  • Pəncərə kliklərə və düymələrə reaksiya vermir.
  • Yenidən çəkilmə dayanır — pəncərəni hərəkət etdirəndə görüntü “donub qalır”.
  • İstifadəçi proqramın “xarab olduğunu” düşünür.

Səhv kod nümunəsi (Swing):

button.addActionListener(e -> {
    // Uzun əməliyyat birbaşa EDT-də!
    longOperation(); // Məsələn, böyük faylın oxunması
    label.setText("Hazırdır!");
});

Nəticə: longOperation() icra olunduğu müddətdə pəncərə istifadəçiyə cavab vermir.

Niyə belə olur? EDT tapşırıqları növbə ilə emal edir və eyni anda yalnız birini yerinə yetirə bilər. O, uzun əməliyyatla məşğul ikən nə klikləri, nə də yenidən çəkilməni işləyə bilir.

3. Həll: uzun əməliyyatlar — yalnız fon axınlarında

Prinsip:

  • Bütün uzun əməliyyatlar — yalnız fon axınlarında.
  • Bütün UI dəyişiklikləri — yalnız EDT/JavaFX Application Thread-də.

Uzun əməliyyatı ayrıca axında işə salaq

Nümunə (Swing):

button.addActionListener(e -> {
    new Thread(() -> {
        longOperation(); // Fon axınında icra olunur
        // İndi UI-ni yeniləmək lazımdır — amma yalnız EDT-dən!
        SwingUtilities.invokeLater(() -> label.setText("Hazırdır!"));
    }).start();
});

Nümunə (JavaFX):

button.setOnAction(e -> {
    new Thread(() -> {
        longOperation();
        // UI-ni Platform.runLater vasitəsilə yeniləyirik
        Platform.runLater(() -> label.setText("Hazırdır!"));
    }).start();
});

UI-ni fon axınından necə yeniləmək olar?

  • Swing: SwingUtilities.invokeLater(Runnable)-dən istifadə edin — tapşırıq EDT növbəsinə düşəcək.
  • JavaFX: Platform.runLater(Runnable)-dən istifadə edin — tapşırıq JavaFX Application Thread-də icra olunacaq.

Niyə sadəcə label.setText(...) fon axınından çağırmaq olmaz? Çünki bu, UI-nin axın təhlükəsizliyini pozur: komponentlər yalnız interfeys axınından dəyişdirilməlidir.

Fon tapşırıqları üçün xüsusi siniflər

Real tətbiqlərdə tez-tez proqresi göstərmək, ləğv etməyə icazə vermək və səhvləri emal etmək lazım olur. Bunun üçün aşağıdakılar var:

  • SwingWorker<T, V> — Swing üçün;
  • Task<V>, Service<V> — JavaFX üçün.

Nümunə (JavaFX Task):

Task<Void> task = new Task<>() {
    @Override
    protected Void call() throws Exception {
        longOperation();
        // Proqresi yeniləmək olar: updateProgress(...)
        return null;
    }
};

task.setOnSucceeded(e -> label.setText("Hazırdır!"));
task.setOnFailed(e -> label.setText("Xəta!"));

new Thread(task).start();

Üstünlüklər: proqres, ləğv etmə, uğur/xəta hadisələri. UI dəyişiklikləri — təhlükəsiz metodlar (updateMessage, updateProgress) və ya emalçılar (setOnSucceeded və s.) vasitəsilə.

4. Düzgün və yanlış nümunələr

Yanlışdır: uzun əməliyyatları hadisə emalçısında icra etmək

button.setOnAction(e -> longOperation()); // UI donacaq!

Doğrudur: uzun əməliyyatlar ayrıca axında

button.setOnAction(e -> new Thread(() -> longOperation()).start());

Daha da yaxşısı: Task/Worker istifadə etmək

JavaFX:

button.setOnAction(e -> {
    Task<Void> task = new Task<>() {
        @Override
        protected Void call() throws Exception {
            longOperation();
            return null;
        }
    };
    task.setOnSucceeded(ev -> label.setText("Hazırdır!"));
    new Thread(task).start();
});

Swing:

button.addActionListener(e -> {
    SwingWorker<Void, Void> worker = new SwingWorker<>() {
        @Override
        protected Void doInBackground() throws Exception {
            longOperation();
            return null;
        }
        @Override
        protected void done() {
            label.setText("Hazırdır!");
        }
    };
    worker.execute();
});

5. Təcrübə: fayl yükləmə nümunəsi

JavaFX:

button.setOnAction(e -> {
    Task<String> task = new Task<>() {
        @Override
        protected String call() throws Exception {
            // Uzun yükləmənin imitasiyası
            Thread.sleep(2000);
            return "Fayl yükləndi!";
        }
    };
    task.setOnSucceeded(ev -> label.setText(task.getValue()));
    new Thread(task).start();
});

Swing:

button.addActionListener(e -> {
    SwingWorker<String, Void> worker = new SwingWorker<>() {
        @Override
        protected String doInBackground() throws Exception {
            Thread.sleep(2000);
            return "Fayl yükləndi!";
        }
        @Override
        protected void done() {
            try {
                label.setText(get());
            } catch (Exception ex) {
                label.setText("Xəta!");
            }
        }
    };
    worker.execute();
});

6. EDT və uzun əməliyyatlarla işləyərkən tipik səhvlər

Səhv №1: Uzun əməliyyatın EDT-də icrası. Bütün tətbiq “donur”, pəncərə reaksiya vermir, istifadəçi proqramın sıradan çıxdığını düşünür.

Səhv №2: UI-ni fon axınından yeniləməyə cəhd. UI-nin axın təhlükəsizliyinin pozulması xətalara, artefaktlara və çökmələrə səbəb ola bilər. SwingUtilities.invokeLater və ya Platform.runLater istifadə edin.

Səhv №3: Fon tapşırığında səhvlərin emal olunmaması. İstisnalar “itirilir”, istifadəçi nəyi səhv getdiyini bilmir. Swing-də — done()-u override edin və get()-i oxuyun; JavaFX-də — setOnFailed-ə abunə olun.

Səhv №4: Uzun əməliyyatı ləğv etmək imkanı yoxdur. İstifadəçi yükləməni/hesablamanı dayandıra bilmir. Ləğv etmə dəstəyindən istifadə edin (SwingWorker.cancel, Task.cancel) və tapşırıq daxilində ləğv bayraqlarını yoxlayın.

Səhv №5: Proqres göstəricisi yoxdur. İstifadəçi proqramın “donduğunu” düşünür. Swing-də — nəticələrin dərcini və proqres çubuğunu SwingWorker ilə birlikdə istifadə edin; JavaFX-də — updateProgress və vizual indikatorlardan istifadə edin.

1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Donmuş lazer idarəetmə pultu 💥
Donmuş lazer idarəetmə pultu 💥
1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Cavab verən lazer idarəetmə pultu ✨
Cavab verən lazer idarəetmə pultu ✨
1
Sorğu/viktorina
, səviyyə, dərs
Əlçatan deyil
Hadisələr və hadisələrin işlənməsi
Hadisələr və hadisələrin işlənməsi
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION