Programmeren in Java/Multithreading

Uit Wikibooks

Programmeren in Java In ontwikkeling. Revisiedatum: onbekend

Inleiding Redelijk ontwikkeld. Revisiedatum: 22 augustus 2008

Installatie In ontwikkeling. Revisiedatum: 26 decemeber 2020

Hulpmiddelen Nog vrijwel niets. Revisiedatum: 26 decemeber 2020
  1. Booleaanse logica Nog vrijwel niets. Revisiedatum: 30 december 2020
  2. Conditionele blokken Goed ontwikkeld. Revisiedatum: 24 april 2021
  3. Lussen Goed ontwikkeld. Revisiedatum: 24 Februari 2021
  4. Methoden Nog vrijwel niets. Revisiedatum: 30 december 2020
  5. Arrays Goed ontwikkeld. Revisiedatum: 30 december 2020
  6. Strings In ontwikkeling. Revisiedatum: 24 november 2007
  7. Exceptions Redelijk ontwikkeld. Revisiedatum: 24 november 2007
  8. Commandoregel-argumenten Goed ontwikkeld. Revisiedatum: 24 Februari 2021
  9. Invoer van een toetstenbord Nog vrijwel niets. Revisiedatum: 24 Februari 2021
  10. Multithreading Nog vrijwel niets. Revisiedatum: 20 januari 2007
  11. GUI In ontwikkeling. Revisiedatum: 24 november 2007
  12. In- & uitvoer In ontwikkeling. Revisiedatum: 24 november 2007
Appendices

Multithreading is het uitvoeren van meerdere taken tegelijkertijd, buiten java ook gekend onder de benaming multitasking. Bij computers die slechts één processor hebben, wordt het werk van de verschillende threads in kleine pakketjes afwisselend uitgevoerd. Als er meerdere processoren aanwezig zijn, kan er echt parallel gewerkt worden.

draad extends Thread[bewerken]

Voorbeelden zijn bvb. het wegschrijven door de tekstverwerker van een bestand op de achtergrond, terwijl je al verdertypt.

Uitdrukkingen
  • public void run() bevat de uit te voeren code.
  • start() creëert de extra thread, en de JVM voert de run() uit.
  • sleep(int mills) om de thread een aantal milliseconden te laten pauzeren.
  • name
  • priority verdeelt de processortijd tussen de verschillende threads. De waarde ligt tussen MIN_PRIORITY (1) en MAX_PRIORITY (10).
Voorbeeld

Java-code: draad.java

public class draad extends Thread {
  private final String naam;
  private final int aantal;
  private final String s;
  public draad(String threadName, String naam, int aantal, int kolom) { // constructor
    super(threadName);
    this.naam = naam;
    this.aantal = aantal;
    final StringBuilder buf = new StringBuilder(kolom + 2);
    for (int j = 0; j < kolom; j++)
      buf.append('\t');
    s = buf.append(" x").toString();
  }
  public void run() {
    for (int i = 0; i < aantal; i++) {
      System.out.println(naam + i + s);
    }
  }           
}

Java-code: multi.java

public class multi {
  public static void main(String[] args) {
    draad reeksA = new draad("taakA", "A", 10, 1);
    draad reeksB = new draad("taakB", "B", 10, 2);
    draad reeksC = new draad("taakC", "C", 10, 3);
    reeksA.start();
    reeksB.start();
    reeksC.start();
  }
}

Als we dit laten lopen, zien we dat het werk mooi verdeeld wordt over de verschillende threads:

A0	 x
B0		 x
C0			 x
A1	 x
B1		 x
C1			 x
...
A8	 x
B8		 x
C8			 x
A9	 x
B9		 x
C9			 x

draad2 implements Runnable[bewerken]

Een iets omslachtiger methode behaalt hetzelfde resultaat als hierboven:

Uitdrukkingen
  • public void run() bevat de uit te voeren code.
  • start()
  • .currentThread().getName()
Voorbeeld

Java-code: draad2.java

public class draad2 implements Runnable{
  private final String naam;
  private final int aantal;
  private final String s;
  public draad2(String naam, int aantal, int kolom) {
    this.naam = naam;
    this.aantal = aantal;
    final StringBuilder buf = new StringBuilder(kolom + 2);
    for (int j = 0; j < kolom; j++)
      buf.append('\t');
    s = buf.append(" x").toString();
  }
  public void run() {
    for (int i = 0; i < aantal; i++) {
      System.out.println(naam + i + s);
    }          
  }
}

Java-code: multi2.java

public class multi2 {
  public static void main(String[] args) {
    draad2 reeksA = new draad2("A", 10, 1); 
    draad2 reeksB = new draad2("B", 10, 2);
    draad2 reeksC = new draad2("C", 10, 3);
    Thread t1 = new Thread(reeksA, "taakA");
    Thread t2 = new Thread(reeksB, "taakB");
    Thread t3 = new Thread(reeksC, "taakC");
    t1.start();
    t2.start();
    t3.start();
  }
}

Synchronisatie[bewerken]

Tegelijk lopende verrichtingen kunnen elkaar storen. Daarom kan je objecten blokkeren, zodat ze slechts door één thread tegelijkertijd kunnen gebruikt worden. Als echter de ene thread wacht op het vrijkomen van een object dat door een andere thread geblokkeerd wordt omdat het eerst het geblokkeerde object van de eerste thread nodig heeft, ontstaat een zgn. deadlock. Dit treedt ook soms op bij databanken, en dan zal een rollback uitgevoerd worden na een bepaalde deadtime.

Uitdrukkingen

In Java kan je dergelijke problemen best voorkomen:

  • wait() zal gedurende een bepaalde periode het object in de wacht zetten
  • notifyAll() haalt alle threads uit de wacht, zodat ze eventueel het object dat net vrijgegeven werd kunnen gebruiken
  • synchronised zorgt dat hiermee gemarkeerde methods niet tegelijkertijd worden uitgevoerd
Voorbeeld

Onderstaande Buffer wordt gevuld door de Producent en geleegd door de Consument, die beiden threads zijn die door het hoofdprogramma Synchro aangestuurd worden:

Java-code: Buffer.java

public class Buffer {
  private String inhoud;
  private boolean vullen = true; //Schakelaar: Starten met opvullen
  public synchronized String haalOp() {
    try {
      while (vullen)             //Wachten op opvulling voor er opgehaald wordt
        wait();
    } catch (Exception e) {}
    vullen = true;
    notifyAll();
    return inhoud;
  }
  public synchronized void vulOp(String inhoud) {
    try {
      while (!vullen)            //Wachten op ophaling voor er opnieuw opgevuld wordt
        wait();
    } catch (Exception e) {}
    this.inhoud = inhoud;
    vullen = false;
    notifyAll();
  }
}

Java-code: Producent.java

public class Producent implements Runnable {
  private String[] tekst;
  private Buffer buf;
  public Producent (String[] tekst, Buffer buf) {
    this.tekst = tekst;
    this.buf = buf;
  }
  public void run() {
    String lijn;
    int r = 0;
    while (r < tekst.length)
      buf.vulOp(lijn = tekst[r++]);
    buf.vulOp(null);
  }
}

Java-code: Consument.java

public class Consument implements Runnable { 
 private Buffer buf;
  private int aantalWoorden;
  public Consument (Buffer buf) {
    this.buf = buf;
    aantalWoorden = 0;
  }
  public void run() {
    String lijn;
    while ((lijn = buf.haalOp()) != null) {
      System.out.println(lijn);
      for (int i = 0; i < lijn.length(); i++) { // woorden tellen
        if (lijn.charAt(i) == ' ') 
          aantalWoorden++;
      }
      System.out.println("\t\tTussentotaal = " + ++aantalWoorden);;
    }
    System.out.println("Totaal aantal woorden = " + aantalWoorden);
  }
}

Java-code: Synchro.java

public class Synchro {
  public static void main(String[] args) {
    String[] tekst = {"Ode aan de vreugde", "Door Filip Muyzenhardt", "Paramaribo"};
    Buffer buf = new Buffer();
    Producent pro = new Producent(tekst, buf);
    Consument con = new Consument(buf);
    Thread t1 = new Thread(pro);
    Thread t2 = new Thread(con);
    t1.start();
    t2.start();
  }
}

Client- en Serverprocessen[bewerken]

Computers op een netwerk, als het internet, werken ook met processen die op elkaar wachten:

Java-code: TCPClient.java

import java.io.*; 
import java.net.*; 

class TCPClient { 
  public static void main(String argv[]) throws Exception { 
    String sentence; 
    String modifiedSentence; 
    
    BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));  //Create input stream
    Socket clientSocket = new Socket("localhost", 6789); //Create client socket, connect to server
    DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream()); // Create output stream attached to socket
    BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); // Create input stream attached to socket
    sentence = inFromUser.readLine(); 
    outToServer.writeBytes(sentence + '\n'); // Send line to server
    modifiedSentence = inFromServer.readLine(); // Read line from server
    System.out.println("FROM SERVER: " + modifiedSentence); 
    clientSocket.close(); 
    
  }
}

Onderstaand proces zal na opstarten de requesten van bovenstaand proces beantwoorden.

Java-code: TCPServer.java

import java.io.*; 
import java.net.*; 

class TCPServer { 
  public static void main(String argv[]) throws Exception { 
    String clientSentence; 
    String capitalizedSentence; 
    
    ServerSocket welcomeSocket = new ServerSocket(6789); // Create welcoming socket at port 6789
    
    while(true) { //loop back and wait for another client connection
      Socket connectionSocket = welcomeSocket.accept(); //Wait, on welcoming socket for contact by client
      BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream())); //Create input stream, attached to socket
      DataOutputStream  outToClient = new DataOutputStream(connectionSocket.getOutputStream()); //Create output stream, attached to socket
      clientSentence = inFromClient.readLine(); //Read in line from socket
      capitalizedSentence = clientSentence.toUpperCase() + "\n !!!"; 
      outToClient.writeBytes(capitalizedSentence); //Write out line to socket
    } 
  } 
}

Termen die met multi threading te maken hebben[bewerken]

Livelock: een thread wacht op een andere thread met bv. Thread.join() totdat hij aan het eind is.
Deadlock: twee of meer threads die zo bezig zijn dat, ze niet meer iets kunnen doen, bv.: thread A wacht totdat thread B eindigt en thread B wacht totdat thread A eindigt

Informatie afkomstig van https://nl.wikibooks.org Wikibooks NL.
Wikibooks NL is onderdeel van de wikimediafoundation.