Datacommunicatie en netwerken Hogeschool Gent Datacommunicatie en netwerken Johan Van Schoor Bert Van Vreckem 2006-2007
Project Groepswerk (per 2) Netwerkapplicatie schrijven in Java Opgaven: zie dokeos ofwel eigen voorstel Evt. combineren met ander vak Deadline: laatste oef les Op tijd! (zoniet sanctie) CD+dossier met afgewerkt product Programma draait zelfstandig, buiten een IDE Gebruikershandleiding Dossier over achterliggende technologie, ontwerp, ... Demo op zie dokeos
Project – opgaven Peer-to-peer filesharing over een LAN Chatprogramma Mailserver Webserver Webcache RFC implementatie Eigen voorstel?
Het belang van threads Onontbeerlijk in netwerkprogramma's (met sockets) Client: Snel reageren op invoer gebruiker Communicatie met de server Server: Verbindingen met verschillende clients tegelijk
Een thread stoppen Door de method run() op een normale manier te laten eindigen: De thread houdt de waarde van een variabele in het oog die aangeeft of de thread moet stoppen Eventueel een extra variabele als je de thread tijdelijk wil stilleggen (“suspend”) NIET met stop(), suspend() of resume(): deprecated
Threads in Java 1.5. De overgang naar 1.5. brengt belangrijke wijzigingen mee i.v.m. multithreading. Gebruiken de Runnable interface ipv een subklasse van Thread. Gebruiken een ThreadPool die threads bevat die de Runnable objecten uitvoeren. Geen start() meer nodig. Synchronisatie gebeurt via lock en unlock op een extra object van de klasse ReentrantLock. De klasse ReentrantLock levert Condition objecten waarmee de synchronisatie tussen de verschillende threads die een object delen kan worden geregeld. await de thread komt in wait state signal de thread komt terug in de runnable state
Voorbeeld: Twee threads (1). import java.util.Random; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; public class ThreadHelloCount { public static void main(String[] args) HelloThread hello = new HelloThread(); CountThread count = new CountThread(); ExecutorService threadExecutor = Executors.newFixedThreadPool(2); threadExecutor.execute( hello ); threadExecutor.execute( count ); threadExecutor.shutdown(); System.out.printf("MainThread finished\n"); }
Voorbeeld: Twee threads (2). class HelloThread implements Runnable { private static Random generator =new Random(); public void run() { for (int i=0; i<5; i++) { try { System.out.printf("Hello!\n"); Thread.sleep(generator.nextInt(3000)); } catch (InterruptedException e) { System.out.println(e.toString()); System.out.printf("HelloThread finished\n");
Voorbeeld: Twee threads (3). class CountThread implements Runnable { private static Random generator = new Random(); public void run() { for (int i=0; i<5; i++) { try { System.out.printf("%d\n",i+1); Thread.sleep(generator.nextInt(3000)); } catch (InterruptedException e) { System.out.println(e.toString()); System.out.printf("CountThread finished\n");
Voorbeeld: Twee threads (4). Mogelijke uitvoer:
Voorbeeld: Thread Synchronisatie (1). public interface Buffer { public void set( int value ); public int get(); } import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; public class SynchronizedBuffer implements Buffer { private Lock accessLock = new ReentrantLock(); private Condition canWrite = accessLock.newCondition(); private Condition canRead = private int buffer; private boolean occupied = false;
Voorbeeld: Thread Synchronisatie (2). public void set( int value ) { accessLock.lock(); try { while ( occupied ) { canWrite.await(); } buffer = value; occupied = true; canRead.signal(); catch ( InterruptedException e ) { e.printStackTrace(); finally { accessLock.unlock();
Voorbeeld: Thread Synchronisatie (3). public int get() { int readValue = 0; accessLock.lock(); try { while ( !occupied ) { canRead.await(); } occupied = false; readValue = buffer; canWrite.signal(); catch ( InterruptedException e ) { e.printStackTrace(); finally { accessLock.unlock(); return readValue;
Voorbeeld: Thread Synchronisatie (4). import java.util.Random; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; public class SynchronizedThreadApp { public static void main(String []arg) { ExecutorService threadExecutor = Executors.newFixedThreadPool(2); Buffer shared = new SynchronizedBuffer(); threadExecutor.execute( new Producer(shared); threadExecutor.execute( new Consumer(shared) ); threadExecutor.shutdown(); }
Voorbeeld: Thread Synchronisatie (5). class Producer implements Runnable { private Buffer shared; private static Random generator = new Random(); public Producer(Buffer sb) { shared=sb; } public void run() { for(int i = 1; i <=10; i++) { try { Thread.sleep(generator.nextInt(2000)); catch (InterruptedException e) { System.out.println(e.toString()); shared.set(i);
Voorbeeld: Thread Synchronisatie (6). class Consumer implements Runnable { private Buffer shared; private static Random generator = new Random(); public Consumer(Buffer sb) { shared=sb; } public void run() { for(int i = 0; i <10; i++) { try { Thread.sleep(generator.nextInt(2000)); catch (InterruptedException e) { System.out.println(e.toString()); System.out.printf("%4d",shared.get()); System.out.println(); Uitvoer: rij getallen van 1 tot 10.
Voorbeeld: Thread Synchronisatie met BlockingQueue (1). import java.util.concurrent.ArrayBlockingQueue; public class BlockingBuffer implements Buffer { private ArrayBlockingQueue<Integer> buffer; public BlockingBuffer() { buffer = new ArrayBlockingQueue<Integer>( 3 ); } public void set( int value ) { try { buffer.put( value ); // indien er geen plaats is // in de queue wordt er gewacht (wait state) catch ( InterruptedException e ) { e.printStackTrace();
Voorbeeld: Thread Synchronisatie met BlockingQueue (2). public int get() { int readValue = 0; try { readValue =buffer.take();//indien er geen waarden // in de queue zijn wordt er gewacht (wait state) } catch ( InterruptedException e ) { e.printStackTrace(); return readValue;
Voorbeeld: Thread Synchronisatie met BlockingQueue (3). import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; public class BlockingBufferThreadApp { public static void main(String []arg) { ExecutorService threadExecutor = Executors.newFixedThreadPool(2); Buffer shared = new BlockingBuffer(); threadExecutor.execute( new Producer(shared) ); threadExecutor.execute( new Consumer(shared) ); threadExecutor.shutdown(); }
Oefening multithreading: Clients requests. Start een “Server thread” en drie “Client Threads”. De clients sturen elk 5 berichten (in dit geval: hun naam) naar de server op met random tijdsverloop (telkens tussen 0 en 3 sec) De server vangt de verschillende berichten op en drukt ze af op console. Na 15 berichten sluit de server thread af.
Oefening multithreading: Clients requests. Mogelijke output :