Wątki (Threads) Concurrent programming is like stepping into an entirely new world and learning a new programming language!!! (grząski grunt) Unikaj jeśli moŝesz! Oparte są zwykle na wielozadaniowym SO (dlatego brak JVM dla DOS, w3.1) Potrzeby One of the most compelling reasons for concurrency is to produce a responsive user interface. Twój program realizuje eksperyment, masz na GUI przycisk <quit>? Sprawdzasz jego stan co pewien odcinek czasu? Przetwarzanie równoległe i współbieŝne Cechy programowania wątkowego Zachowanie wątków jest zaleŝne od platformy program wielowątkowy moŝe być wolniejszy! W Javie mamy 10 poziomów priorytetu (Solaris 2 31, NT 7) Thread.MAX_PRIORITY, Thread.NORM_PRIORITY, Thread.MIN_PRIORITY A thread can be preempted at any time by another thread Szeregowanie rotacyjne Przeplot czasowy 1
Klasa Thread Klasa Thread nie jest wątkiem! Klasa moŝe być kontrolerem wątku Z faktu Ŝe zdefiniujemy jakąś metodę w klasie pochodnej od Thread nie oznacza, Ŝe działa ona w osobnym wątku! Thread c.d. start( ) //special initialization and then calls run( ). output for one run of this program will be different from that of another!!! thread scheduling mechanism is not deterministic! Pierwszy sposób class simplethread extends Thread { public SimpleThread (String s) { super(s) ; for (int i=0; i<10; i++) { System.out.println(i+ getname()); Przykład wykorzystania class ThreeThreads { main(string[] args) { new SimpleThread( Pierwszy ).start() ; new SimpleThread( Drugi ).start() ; new SimpleThread( Trzeci ).start() ; 2 sposób Interfejs Runnable Przykład Obiekt, który chce być kontrolerem wątku (określać co wątek ma robić) powinien wskazać Ŝe dysponuje odpowiednią metodą wykonawczą deklarując implementację interfejsu Runnable w którym zdefiniowano metodę: public interface Runnable { abstract public void run(); Obiekty klas implementujących interfejs Runnable moŝemy określić jako wykonywalne (aktywne) gdyŝ mogą być podstawą do uruchomienia wątku KaŜdy obiekt moŝe być kontrolerem wątku (klasa moŝe implementować dowolna liczbę interfejsów) class Animation implements Runnable { while ( true ) { // Draw Frames repaint(); Animation happy = new Animation("Mr. Happy"); Thread mythread = new Thread( happy ); mythread.start(); 2
Przykład Usypianie wątku Thread.sleep ( 1000 ); catch ( InterruptedException e ) { Zakończenie wątku Wątek kończy działanie gdy wystąpi jeden z trzech przypadków: returns from its target run() method interrupted by an uncaught exception before Java 1.2 its stop() method is called public final void stop() Deprecated. This method is inherently unsafe. run() while(true) { System.out.println(this); if(--countdown == 0) return; sleep(100); catch (InterruptedException e) { throw new RuntimeException(e); Thread states Synchronizacja wątków NEW A thread that has not yet started is in this state. RUNNABLE A thread executing in the Java virtual machine is in this state. BLOCKED A thread that is blocked waiting for a monitor lock is in this state. WAITING A thread that is waiting indefinitely for another thread to perform a particular action is in this state. TIMED_WAITING A thread that is waiting for another thread to perform an action for up to a specified waiting time is in this state. TERMINATED A thread that has exited is in this state. Synchronizacja wątków w języka Java bazuje na koncepcji monitorów opracowanej przez C.A.R. Hoare. Monitor spełnia rolę zamka związanego z współuŝytkowanym zasobem. Jeśli zasób jest wolny obejmujesz go (drzwi otwarte wchodzisz i zamykasz). Po zakończeniu uŝywania zwalniasz (otwierasz, wychodzisz następna osoba moŝe skorzystać). Jeśli zasób jest zajęty wątek musi czekać. Monitory związane są z obiektami. Słowo kluczowe synchronized słuŝy do oznaczenia miejsca, w którym wątek musi objąć monitor. Oznaczona tym słowem aktywność wykonuje się niepodzielnie* 3
Metody synchronizowane class SpreadSheet { int cella1, cella2, cella3; synchronized int sumrow() { return cella1 + cella2 + cella3; synchronized void setrow( int a1, int a2, int a3 ) { cella1 = a1; cella2 = a2; cella3 = a3; Synchronizowany blok synchronized ( myobject ) { // Functionality that needs to be synced synchronized void mymethod () { is equivalent to: void mymethod () { synchronized ( this ) { wait() notify() By executing wait() from a synchronized block, a thread gives up its hold on the lock and goes to sleep. A thread might do this if it needs to wait for something to happen in another part of the application. Later, when the necessary event happens, the thread that is running it calls notify() from a block synchronized on the same object. Now the first thread wakes up and begins trying to acquire the lock again. Problem Producent - konsument class Producer extends Thread { static final int MAXQUEUE = 5; private Vector messages = new Vector(); while ( true ) { putmessage(); sleep( 1000 ); catch( InterruptedException e ) { Konsument putmessage() class Consumer extends Thread { while ( true ) { String message = producer.getmessage(); System.out.println("Got message: " + message); sleep( 2000 ); catch( InterruptedException e ) { private synchronized void putmessage() throws InterruptedException { while ( messages.size() == MAXQUEUE ) wait(); messages.addelement( new java.util.date().tostring() ); notify(); 4
getmessage() // Called by Consumer public synchronized String getmessage() throws InterruptedException { notify(); while ( messages.size() == 0 ) wait(); String message = (String)messages.firstElement(); messages.removeelement( message ); return message;??? Gdzie powinny być umieszczone metody getmessage() i putmessage() Wątki w komponencie public class Kompas extends Component implements Runnable { Int azymut, newazymut ; Thread compasthread ; public Kompas(int azymut) { // konstruktor this.azymut = this.newazymut = azymut ; compasthread = new Thread(this); compasthread.start(); //end of constructor Metoda run() public void run () { while(true) { if (newazymut!= azymut ) { Thread.currentThread().sleep(100); catch (InterruptedException e) { // obsługa błędu azymut++; azymut %=360; repaint(); //end of while Setter Źródło impulsów public void setazymut (int newazymut) { this.newazymut = newazymut; // repaint(); Thread does it instead public class PulseGenerator extends Thread implements PulseSource byte mode ; boolean on ; public PulseGenerator() { mode = PulseSource.BURST_MODE ; start() ; 5
Źródło impulsów while (on) { // fire up pulse event // test mode & check if last pulse // sleep for a moment public void halt() { on = false ; public void trigger() {??? 6