Thread.Runnable i przekazanie do new Thread(runnable).Runnable (lepsza separacja logiki zadania od mechanizmu wykonania).class CounterThread extends Thread { @Override public void run() { for (int i = 1; i <= 5; i++) { System.out.println(getName() + " -> " + i); try { Thread.sleep(200); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } } } // użycie CounterThread t1 = new CounterThread(); t1.start();
class PrintTask implements Runnable { private final String label; PrintTask(String label) { this.label = label; } @Override public void run() { System.out.println("Start: " + label + ", thread=" + Thread.currentThread().getName()); } } // użycie Thread t = new Thread(new PrintTask("Import danych")); t.start();
start() - uruchomienie nowego wątku.run() - ciało zadania (wywoływane w nowym wątku po start()).sleep(ms) - pauza.join() - blokuje wątek wywołujący, czekając na zakończenie tego wątku.isAlive() - czy wątek jeszcze działa.interrupt() - sygnał przerwania.setName(), getName(), setPriority(), getPriority(), isInterrupted(), getState(), itd.Dokumentacja: Thread (Java SE 17 & JDK 17)
NEW - utworzony (nie uruchomiony).RUNNABLE - gotowy lub wykonywany.BLOCKED - zablokowany, czeka na monitor (synchronized).WAITING - czeka na powiadomienie bez limitu (np. wait(), join()).TIMED_WAITING - czeka z limitem (sleep(), wait(timeout)).TERMINATED - zakończony.Thread worker = new Thread(() -> { try { Thread.sleep(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }); worker.start(); // uruchomienie wątku System.out.println(worker.isAlive()); // zwykle true worker.join(); // czeka aż worker zakończy System.out.println(worker.isAlive()); // false
stop(), suspend() i resume() są przestarzałe (deprecated) i niebezpieczne.stop() może przerwać wątek w środku sekcji krytycznej.suspend() może zatrzymać wątek trzymający blokadę i zablokować cały system.resume() nie naprawia problemów projektowych i utrudnia przewidywalność.interrupt() i współpracy kodu wątku.Thread.currentThread().isInterrupted().InterruptedException ustaw flagę ponownie i zakończ pracę.class Worker implements Runnable { @Override public void run() { while (!Thread.currentThread().isInterrupted()) { // porcja pracy try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } }
Object implementuje metody wait(), notify() i notifyAll().synchronized na metodzie lub bloku kodu = wejście do monitora obiektu (sekcja krytyczna).class SafeCounter { private int value; // metoda synchronizowana na całym obiekcie public synchronized void inc() { value++; } public int get() { // blok synchronizowany na tym obiekcie synchronized (this) { return value; } } }
wait() zwalnia monitor i usypia wątek do czasu notyfikacjinotify() budzi jeden czekający wątek.notifyAll() budzi wszystkie czekające.while, nie w if, ponieważ po obudzeniu warunek może być już nieprawdziwy (np. inny wątek mógł przejąć monitor i zmienić stan).class OneSlotBuffer { private Integer value = null; public synchronized void put(int v) throws InterruptedException { while (value != null) { wait(); // czeka aż konsument pobierze wartość } value = v; notifyAll(); } public synchronized int take() throws InterruptedException { while (value == null) { wait(); // czeka aż producent wstawi wartość } int result = value; value = null; notifyAll(); return result; } }
Thread.MIN_PRIORITY (1) do Thread.MAX_PRIORITY (10).Thread.NORM_PRIORITY (5).ExecutorService - zarządzanie pulą wątków i zadaniami.AtomicIntegerFork/JoinPool - efektywne dzielenie zadań na mniejsze kawałki.Lock i ReentrantLock - bardziej elastyczne blokady niż synchronized.Semaphore, CountDownLatch, CyclicBarrierConcurrentHashMap, CopyOnWriteArrayList, itp.x++ nie są atomowe.class BrokenCounter { int value = 0; void inc() { value++; } }
synchronized - prosty i bezpieczny punkt startowy.AtomicInteger - atomowe operacje bez jawnych blokad.Lock (np. ReentrantLock) - większa kontrola.import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class LockCounter { private final Lock lock = new ReentrantLock(); private int value = 0; void inc() { lock.lock(); try { value++; } finally { lock.unlock(); } } }
Semaphore kontroluje liczbę jednoczesnych wejść do zasobu.import java.util.concurrent.Semaphore; Semaphore semaphore = new Semaphore(3); // max 3 równolegle semaphore.acquire(); try { // sekcja z ograniczonym dostępem } finally { semaphore.release(); }
Thread, używamy puli wątków.submit(), invokeAll(), shutdown(), awaitTermination().import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; ExecutorService pool = Executors.newFixedThreadPool(4); pool.submit(() -> System.out.println("zadanie A")); pool.shutdown();
Runnable nie zwraca wyniku i nie deklaruje wyjątku.Callable<T> zwraca wynik typu T i może rzucać wyjątek.Future<T> reprezentuje wynik obliczenia w tle.import java.util.concurrent.*; ExecutorService pool = Executors.newSingleThreadExecutor(); Future<Integer> f = pool.submit(() -> 40 + 2); Integer result = f.get(); // może blokować pool.shutdown();
divide and conquer)RecursiveTask<V> oraz RecursiveAction.tryLock() dla krytycznych operacji.java.util.concurrent.Nieprzechwycony i nieobsłużony wyjątek spowoduje przejście wątku do stanu TERMINATED
Wyjątki, które mogą wystąpić w kodzie współbieżnym:
InterruptedException - rzucany, gdy wątek jest przerwany podczas oczekiwania, snu lub innej operacji blokującejIllegalMonitorStateException - wait/notify wołany, gdy wątek nie posiada monitora obiektuIllegalThreadStateException - np. próba uruchomienia wątku, który już został uruchomionySecurityException - próba operacji, do której wątek nie ma uprawnieńfinally.Thread Runnable.synchronized i AtomicInteger.wait() i notify().suspend() i resume().wait()), notify()), getState()).Napisz program, który wyznacza liczbę liczb pierwszych w zakresie od 2 do N wielowątkowo. Program sporządza porównanie szybkości działania w zależności od liczby wątków i pokazuje przyspieszenie względem wersji jednowątkowej.
Wymagania:
Runtime.getRuntime().availableProcessors().Program powinien wypisać, najlepiej w formie tabeli, dla każdej liczby wątków K=1,2,4,…:
Thread API (Java 17): Threadjava.util.concurrent API: java.util.concurrentExecutorService API: ExecutorServiceLock API: Lock