CodeGym /Kurslar /JAVA 25 SELF /Prosesin həyat dövrünün idarə edilməsi

Prosesin həyat dövrünün idarə edilməsi

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

1. Prosesin başa çatmasını gözləmək: waitFor()

Java-dan xarici proses işə salanda, o, öz həyatını yaşayır: nəsə hesablayır, konsola yazır, bəzən asılır (salam, milyon paketlə ping). Amma bəzən bizə lazımdır ki, bu proses nə vaxt və necə başa çatdı (uğur, yoxsa uğursuzluq), və — əgər nəsə səhv gedibsə — onu «öldürməyi» bacaraq. Ümumiyyətlə, real həyatda olduğu kimi: kiməsə tapşırıq verdinizsə, necə öhdəsindən gəldiyini bilmək və o, birdən sonsuzluğa qədər qəhvə «bişirməyə» başlasa, dayandırmaq imkanı yaxşı olardı.

Prosesləri ProcessBuilder vasitəsilə işə salanda, siz Process tipli obyekt alırsınız. Bu obyekt — sanki idarəetmə pultudur: onunla prosesin tamamlanmasını gözləmək, çıxış kodunu əldə etmək, prosesi bitirmək və giriş‑çıxış axınlarını idarə etmək mümkündür.

Prosesin başa çatmasını necə gözləmək?

Bunun üçün waitFor() metodu var:

ProcessBuilder builder = new ProcessBuilder("ping", "google.com", "-c", "3");
Process process = builder.start();

System.out.println("Prosesin tamamlanmasını gözləyirik...");
int exitCode = process.waitFor(); // Cari thread-i proses başa çatana qədər bloklayır
System.out.println("Proses bu kodla başa çatdı: " + exitCode);

Nə baş verir?

  • Proqram xarici prosesi işə salır (ping).
  • Bundan sonra waitFor() çağırılan thread, xarici proses bitənədək «yuxuya gedir».
  • Xarici proses işi bitirən kimi, waitFor() çıxış kodunu qaytarır (adətən 0 — uğur, 0 deyil — xəta).

Çıxış kodunu necə öyrənmək olar?

Bu kodu waitFor() qaytarır. Həmçinin onu ayrıca exitValue() ilə də almaq olar:

int code = process.exitValue();

Ancaq ehtiyatlı olun: əgər proses hələ başa çatmayıbsa, exitValue() çağırışı IllegalThreadStateException istisnasını atacaq. Buna görə, adətən əvvəlcə waitFor() ilə tamamlanmanı gözləyir, sonra kodu yoxlayırlar.

2. Prosesin dayandırılması: destroy()destroyForcibly()

Bəzən xarici proses həddən artıq uzun işləyir və ya asılır. Məsələn, kimsə ping-i 1000 paketlə işə salıb, sizdə isə 5 saniyəyə deadline var. «Qırmızı düymə» lazımdır.

Yumşaq dayandırma: destroy()

destroy() metodu prosesə tamamlanma siqnalı göndərir (Unix-də SIGTERM, Windows-da CTRL-BREAK) və prosesə səliqəli şəkildə bitirmək üçün şans verir.

Process process = new ProcessBuilder("ping", "google.com").start();

Thread.sleep(2000); // 2 saniyə işləsin
process.destroy(); // Bitirməyi xahiş edirik

Sərt dayandırma: destroyForcibly()

Proses nəzakətli xahişlərə reaksiya vermirsə, destroyForcibly() metodundan istifadə edə bilərsiniz. Bu, sanki ştepseli rozetkadan çıxarmaq kimidir.

process.destroyForcibly();

Vacibdir: destroy() və ya destroyForcibly() çağırışından sonra prosesi waitFor() ilə tam bitənədək gözləmək lazımdır. Bəzən proses «öz ölümünü» dərk etmək üçün vaxta ehtiyac duyur.

3. Taymautla proses gözləmə

Java 8+‑da taymautlu metod peyda olub:

boolean finished = process.waitFor(5, java.util.concurrent.TimeUnit.SECONDS);
if (finished) {
    System.out.println("Proses vaxtında başa çatdı!");
} else {
    System.out.println("Proses başa çatmadı, dayandırırıq...");
    process.destroy();
}
  • Əgər proses 5 saniyə ərzində başa çatıbsa, metod true qaytaracaq.
  • Əks halda — false qaytaracaq və siz tədbir görə bilərsiniz (məsələn, prosesi bitirmək).

Nümunə: Uzun çəkən komandanı işə salaq və onu «öldürməyə» cəhd edək:

ProcessBuilder builder = new ProcessBuilder("ping", "google.com", "-c", "10");
Process process = builder.start();

boolean finished = process.waitFor(2, java.util.concurrent.TimeUnit.SECONDS);
if (!finished) {
    System.out.println("Proses çox uzun işləyir, dayandırırıq...");
    process.destroy();
    // Tam başa çatmasını gözləmək olar
    process.waitFor();
}
System.out.println("Çıxış kodu: " + process.exitValue());

4. Təcrübə: taymautlu komandaya start verən mini‑utilit

Gəlin sadə bir proqram yazaq: xarici komandanı taymautla işə salır, onun tamamlanmasını gözləyir, vaxt aşılarsa — prosesi bitirir.

import java.io.IOException;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;

public class ProcessTimeoutDemo {
    public static void main(String[] args) throws IOException, InterruptedException {
        Scanner scanner = new Scanner(System.in);

        System.out.println("İcra etmək üçün komanda daxil edin (məsələn, ping google.com):");
        String commandLine = scanner.nextLine();
        String[] command = commandLine.split(" ");

        ProcessBuilder builder = new ProcessBuilder(command);
        Process process = builder.start();

        System.out.println("Tamamlanmanı nə qədər saniyə gözləmək lazımdır?");
        int timeout = scanner.nextInt();

        boolean finished = process.waitFor(timeout, TimeUnit.SECONDS);
        if (finished) {
            System.out.println("Proses özü başa çatdı. Çıxış kodu: " + process.exitValue());
        } else {
            System.out.println("Vaxt bitdi! Prosesi dayandırırıq...");
            process.destroy();
            process.waitFor();
            System.out.println("Proses məcburi dayandırıldı. Çıxış kodu: " + process.exitValue());
        }
    }
}

İzah:

  • İstifadəçi işə salınmalı komandını daxil edir.
  • Proqram göstərilən müddəti gözləyir.
  • Proses başa çatmazsa — onu dayandırır.

Lifehack: Windows-da ping standart olaraq 4 dəfə ping edir, Linux-da isə sonsuzluğa qədər. Linux/Mac üçün -c 5 parametrini əlavə edin (məsələn, ping google.com -c 5).

5. Çıxış kodunun alınması: bu nədir və nə üçün?

Əmr sətri dünyasında qayda belədir: əmr uğurla başa çatıbsa, 0 kodunu qaytarır. Nəsə səhv gedibsə — hər hansı digər kod.

  • Unix‑tipli sistemlərdə: 0 = uğur, 1 və daha yuxarı = xəta.
  • Windows-da — təxminən eynidir.

Bu koddan Java proqramınızda qərar qəbul etmək üçün istifadə edə bilərsiniz:

int exitCode = process.waitFor();
if (exitCode == 0) {
    System.out.println("Uğurludur!");
} else {
    System.out.println("Xəta! Kod: " + exitCode);
}

6. Asılmış proseslərin dayandırılması

Bəzən proses sadəcə asa bilər — məsələn, sizdən nəsə daxil etməyinizi gözləyir və ya şəbəkəyə qoşula bilmir. Nəzarətsiz qoysanız, sistemdə asılı vəziyyətdə qalacaq və resursları «yeyəcək».

Bunun qarşısını almaq üçün prosesə səbr həddi təyin edin. waitFor(timeout, unit) metodu prosesin yalnız müəyyən vaxta qədər gözlənməsinə imkan verir. Vaxta sığışmadısa — tərəddüd etmədən dayandırın.

destroy() çağırışından sonra sadəcə əl sallamaq yox, prosesin doğrudan da getdiyinə əmin olmaq vacibdir. Bunun üçün yenidən waitFor() çağırılır. Bu da kömək etməzsə — son çarə var, destroyForcibly(). O, artıq əlavə söhbətsiz hər şeyi kəsir.

İki mərhələli dayandırma nümunəsi

boolean finished = process.waitFor(5, TimeUnit.SECONDS);
if (!finished) {
    process.destroy();
    if (!process.waitFor(2, TimeUnit.SECONDS)) {
        process.destroyForcibly();
    }
}

Process ilə işin xüsusiyyətləri: nələri yadda saxlamaq lazımdır

Proses başa çatdıqda, onu dərhal unutmağa tələsməyin. Onun çıxışına baxın — həm adi, həm də xətaların saxlandığı kanala. Orada vacib bir şey ola bilər: nasazlıq mesajı, xəbərdarlıq və ya sadəcə hər şeyin uğurla keçdiyini təsdiq edən məlumat.

Bundan sonra əlaqəli bütün axınları mütləq bağlayın — InputStream, OutputStreamErrorStream. Bu, çıxarkən işığı söndürmək kimidir: resurslara qənaət edir və sistemdə nizamı qoruyur.

Və yadınızda saxlayın: prosesi məcburi dayandırmısınızsa, o, öz çıxışını səliqə ilə yazıb bitirməyə macal tapmaya bilər. Qorxulu deyil — belə vəziyyətlər üçün bu, təbii davranışdır.

7. Nümunə: uzunmüddətli əmri işə salmaq və onu dayandırmaq

Tutaq ki, uzunmüddətli prosesi (məsələn, çox sayda paketlə ping) işə salmaq və 3 saniyədən sonra onu dayandırmaq istəyirik.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.TimeUnit;

public class KillLongProcessDemo {
    public static void main(String[] args) throws IOException, InterruptedException {
        String[] command = {"ping", "google.com"};
        // Linux/Mac üçün: {"ping", "google.com", "-c", "100"}
        ProcessBuilder builder = new ProcessBuilder(command);
        Process process = builder.start();

        // Prosesin çıxışını ayrı thread-də oxuyuruq
        Thread readerThread = new Thread(() -> {
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    System.out.println(line);
                }
            } catch (IOException e) {
                // Gözardı edirik
            }
        });
        readerThread.start();

        // 3 saniyə gözləyirik
        if (!process.waitFor(3, TimeUnit.SECONDS)) {
            System.out.println("Proses çox uzun işləyir, dayandırırıq...");
            process.destroy();
            process.waitFor();
        }
        readerThread.join(); // Çıxışın oxunmasını gözləmək
        System.out.println("Proses tamamlandı. Çıxış kodu: " + process.exitValue());
    }
}

8. Proseslərin idarə olunmasında tipik səhvlər

Səhv №1: Prosesin başa çatmasını gözləməmək. Proses işə salınıb və siz onu sadəcə unutmusanızsa (waitFor() çağırmamsınızsa), proses sizin Java proqramınız bitəndən sonra belə sistemdə «asılı» qala bilər. Giriş‑çıxış axınları bağlanmaya bilər, bu isə yaddaş və fayl deskriptoru sızmalarına gətirib çıxarar.

Səhv №2: Prosesin səhv dayandırılması. destroy() çağırdınız, amma prosesi waitFor() ilə bitənədək gözləmədiniz. Nəticədə proses «zombi» kimi qala bilər (xüsusilə Unix sistemlərində).

Səhv №3: Proses başa çatmadan çıxış kodunu gözləmək. Proses bitməmiş exitValue() çağırışı IllegalThreadStateException istisnasına səbəb olur.

Səhv №4: İstisnaları emal etməmək. Proseslə iş metodları IOExceptionInterruptedException ata bilər. Onları tutmağı və ya metodun siqnaturasında elan etməyi unutmayın.

Səhv №5: Prosesin çıxışını oxumamaq. stdoutstderr oxunmazsa, proses çıxış buferinin dolması səbəbindən asa bilər.

Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION