1. Parametrlərin axınlara ötürülməsi
Axını işə salanda tez-tez ona hansısa “iş” ötürmək istəyirsiniz: fayl adı, ədədlər diapazonu və ya salamlaşma. Parametrsiz axın — ünvanı olmayan kuryer kimidir: şəhərdə qaçır, amma pizzanı hara çatdıracağını bilmir.
Bu necə edilir?
Java-da axınlar adətən iki yolla yaradılır:
- Thread sinfindən miras almaq
- Runnable interfeysini həyata keçirmək (və ya lambda ifadəsindən istifadə etmək)
Parametrlər çox vaxt konstruktor vasitəsilə ötürülür — Runnable həyata keçirən sinfin konstruktoru ilə. Bu sadə, təhlükəsiz və anlaşıqlıdır. Sahələri final edin — beləliklə parametrləri digər axınların dəyişməsindən qorumuş olursunuz. Setter-lərdən/ictimai sahələrdən istifadə sinxronizasiya problemlərinə gətirə bilər.
Nümunə 1: Konstruktor vasitəsilə parametrli axın
Tədris tətbiqini təkmilləşdirək: istifadəçi sifarişlərinin ayrıca axında emalı.
public class OrderProcessor implements Runnable {
private final String orderId;
public OrderProcessor(String orderId) {
this.orderId = orderId;
}
@Override
public void run() {
System.out.println("Sifarişi emal edirəm: " + orderId + " axınında " + Thread.currentThread().getName());
// Burada uzunmüddətli emal ola bilər...
}
}
Axınları yaradır və işə salırıq:
public class Main {
public static void main(String[] args) {
Thread thread1 = new Thread(new OrderProcessor("ORDER-001"));
Thread thread2 = new Thread(new OrderProcessor("ORDER-002"));
thread1.start();
thread2.start();
}
}
Gözlənilən çıxış:
Sifarişi emal edirəm: ORDER-001 axınında Thread-0
Sifarişi emal edirəm: ORDER-002 axınında Thread-1
Nümunə 2: Lambda ifadəsi ilə parametrli axın (Java 8+)
Tapşırıq sadədirsə, ayrıca sinfə ehtiyac yoxdur.
public class Main {
public static void main(String[] args) {
String user1 = "Vasya";
String user2 = "Katya";
Thread thread1 = new Thread(() -> {
System.out.println("Salam, " + user1 + " " + Thread.currentThread().getName() + "-dən");
});
Thread thread2 = new Thread(() -> {
System.out.println("Salam, " + user2 + " " + Thread.currentThread().getName() + "-dən");
});
thread1.start();
thread2.start();
}
}
Niyə parametrləri ötürmək üçün setter/getter istifadə etməyə dəyməz?
Parametrləri setter-lər və ya ictimai sahələr vasitəsilə ötürsəniz, risk yaranır ki, başqa bir axın icra zamanı dəyəri dəyişsin. Bu, çətin izlənən səhvlərə səbəb ola bilər. Sahələri final edin və parametrləri konstruktorla ötürün.
2. Axın prioritetləri
Java-da hər axının prioriteti var — 1-dən 10-a qədər tam ədəd; bu, planlayıcıya (scheduler) həmin axının başqaları ilə müqayisədə nə qədər “vacib” olduğunu bildirir. Susmaya görə bütün axınların prioriteti 5-dir (Thread.NORM_PRIORITY).
Vacibdir: prioritet — OS üçün sadəcə “işarə”dir. Bu, prioriteti 10 olan axının prioriteti 1 olan axından mütləq daha sürətli işləyəcəyi zəmanəti deyil. Hər şey OS-dən, onun ayarlarından və cari yüklənmədən asılıdır.
Prioritet axına necə verilir?
Thread sinfində belə metodlar var:
- setPriority(int newPriority)
- getPriority()
Və üç standart sabit:
- Thread.MIN_PRIORITY (1)
- Thread.NORM_PRIORITY (5)
- Thread.MAX_PRIORITY (10)
Nümunə 3: Axına prioritetin təyin edilməsi
public class PriorityDemo {
public static void main(String[] args) {
Runnable task = () -> {
System.out.println("Axın " + Thread.currentThread().getName() +
" prioriteti " + Thread.currentThread().getPriority());
};
Thread low = new Thread(task, "LowPriority");
Thread norm = new Thread(task, "NormalPriority");
Thread high = new Thread(task, "HighPriority");
low.setPriority(Thread.MIN_PRIORITY); // 1
norm.setPriority(Thread.NORM_PRIORITY); // 5
high.setPriority(Thread.MAX_PRIORITY); // 10
low.start();
norm.start();
high.start();
}
}
Gözlənilən çıxış (sətirlərin sırası zəmanətli deyil!):
Axın LowPriority prioriteti 1
Axın HighPriority prioriteti 10
Axın NormalPriority prioriteti 5
Prioritet icra ardıcıllığına təsir edirmi?
Əksər hallarda — xeyr. Prioritetlər prosessorun axına nə qədər vaxt ayırmasına təsir göstərə bilər, amma start və ya tamamlanma ardıcıllığına zəmanət vermir. Proqram məntiqini prioritetlər üzərində qurmayın — onları “yumşaq” məsləhətlər kimi istifadə edin, məsələn, fon axını əsas axına mane olmasın deyə.
Cədvəl: Axın prioritetlərinin sabitləri
| Sabit | Dəyər | Təsvir |
|---|---|---|
|
1 | Ən aşağı prioritet |
|
5 | Adi prioritet |
|
10 | Ən yüksək prioritet |
3. Axınların adlandırılması
Axının adı — çoxvəzifəlilik dünyasında “ləqəb” kimidir. Onlarla axınınız olanda, loqda "Thread-7" əvəzinə "FileUploader-1" görmək sazlamağı asanlaşdırır. Bu, xüsusilə loqların təhlilində və səhvlərin tapılmasında vacibdir.
Axına adı necə vermək olar?
Adı birbaşa Thread konstruktorunda göstərmək və ya setName metodu ilə təyin etmək olar. Cari adı öyrənmək — getName.
Thread t = new Thread(() -> {
System.out.println("Mən işləyirəm!");
}, "MyThreadName");
t.start();
Nümunə 4: Adlandırılmış axınlar
public class NamedThreads {
public static void main(String[] args) {
Thread threadA = new Thread(() -> {
System.out.println("Mən axınam: " + Thread.currentThread().getName());
}, "Downloader");
Thread threadB = new Thread(() -> {
System.out.println("Mən axınam: " + Thread.currentThread().getName());
});
threadB.setName("Uploader");
threadA.start();
threadB.start();
}
}
Gözlənilən çıxış:
Mən axınam: Downloader
Mən axınam: Uploader
4. Təcrübə: müxtəlif parametrlər, prioritetlər və adlarla bir neçə axın
Hər şeyi bir nümunədə birləşdirək: hər sifariş — öz adına və prioritetinə malik ayrıca axın.
public class OrderProcessor implements Runnable {
private final String orderId;
private final int processingTimeMs;
public OrderProcessor(String orderId, int processingTimeMs) {
this.orderId = orderId;
this.processingTimeMs = processingTimeMs;
}
@Override
public void run() {
System.out.println("[" + Thread.currentThread().getName() + "] Sifarişin emalına başladım " + orderId +
" (prioritet " + Thread.currentThread().getPriority() + ")");
try {
Thread.sleep(processingTimeMs); // işin təqlidi
} catch (InterruptedException e) {
System.out.println("[" + Thread.currentThread().getName() + "] Dayandırıldı!");
}
System.out.println("[" + Thread.currentThread().getName() + "] Sifarişin emalını tamamladım " + orderId);
}
public static void main(String[] args) {
Thread fastOrder = new Thread(new OrderProcessor("FAST-ORDER", 500), "FastOrderThread");
Thread normalOrder = new Thread(new OrderProcessor("NORMAL-ORDER", 1000), "NormalOrderThread");
Thread slowOrder = new Thread(new OrderProcessor("SLOW-ORDER", 2000), "SlowOrderThread");
fastOrder.setPriority(Thread.MAX_PRIORITY);
normalOrder.setPriority(Thread.NORM_PRIORITY);
slowOrder.setPriority(Thread.MIN_PRIORITY);
fastOrder.start();
normalOrder.start();
slowOrder.start();
}
}
Nələri görəcəyik:
- Hər axın hansı sifarişi emal etdiyini, öz adını və prioritetini yazır.
- Emal vaxtı Thread.sleep ilə imitasiya olunur.
- Axınların tamamlanma ardıcıllığı prioritetlə uyğun gəlməyə bilər.
5. Vacib nüanslar və xüsusiyyətlər
Parametrlərin ötürülməsi: yalnız konstruktor vasitəsilə!
Bu, daha təhlükəsizdir. Parametrləri final kimi elan edin — obyekt yaradıldıqdan sonra onlar dəyişdirilə bilməz və heç bir başqa axın “öz” dəyərlərini sızdıra bilməz. Bu, məlumat yarışı (data race) riskinin qarşısını almaq üçün çox vacibdir.
Prioritetlər: biznes məntiqini onların üzərində qurmayın
Prioritetlər ofisianta belə bir xahiş kimidir: “Qəhvəni bir az tez gətirə bilərsiniz?” Bəzən işləyir, bəzən — yox. Bu, OS üçün tövsiyədir, icra qaydası deyil.
Axın adları: sazlama üçün istifadə edin
Loqların təhlilində böyük vaxt qazandırır. Dərhal mənalı adlar verməyə vərdiş edin.
6. Parametrlər və prioritetlərlə işləyərkən tipik səhvlər
Səhv №1: Parametrlərin ictimai sahələr vasitəsilə ötürülməsi. Parametrləri adi sahələr kimi elan edib axın startından sonra dəyişsəniz, qeyri-proqnozlaşdırılan nəticələr ala bilərsiniz. final sahələrdən və konstruktordan istifadə edin.
Səhv №2: Prioritetin ardıcıllığı zəmanətli etdiyini zənn etmək. Thread.MAX_PRIORITY qoydunuz — və düşünürsünüz, axın həmişə birinci olacaq? Xeyr. Prioritetləri sinxronizasiya və ya məntiqin idarəsi üçün istifadə etməyin.
Səhv №3: Loqlarda adsız axınlar. Loqlarda yalnız “Thread-3”, “Thread-7” varsa, günahkarı tapmaq çətindir. Konstruktordan və ya setName ilə axınlara mənalı adlar verin.
Səhv №4: Bir neçə axın üçün eyni Runnable obyektindən istifadə. Əgər Runnable obyekti vəziyyət saxlayırsa və onu bir neçə axına ötürürsünüzsə, onlar parametrləri “bölüşürlər” — bu, məlumat yarışına birbaşa yoldur. Hər axın üçün ayrıca Runnable yaradın.
Səhv №5: Parametrlərin set-metodlarla ötürülməsi. Parametrləri obyekti yaratdıqdan/axını işə saldıqdan sonra set* metodları ilə təyin etsəniz, dəyərlər “uçuş zamanı” dəyişə bilər — klassik race condition.
GO TO FULL VERSION