Ungefär motsvarande föreläsningsanteckningar från förra året: Tråd- och nätverksdelarna av java013.pdf
Moderkort för en fysisk processor |
Moderkort för två fysiska processorer |
Metod:public class BoringThread extends Thread { public void run() { while (true) ; } // run public static void main(String[] args) { BoringThread t1 = new BoringThread(); t1.start(); BoringThread t2 = new BoringThread(); t2.start(); } // main } // class BoringThread
Körexempel:public class BoringThread2 extends Thread { static int numberOfThreads = 0; int threadNumber = ++numberOfThreads; public void run() { int nrReps = 0; while (true) { System.out.println("Tråd " + threadNumber + " har kört " + ++nrReps + " varv i loopen."); } } // run public static void main(String[] args) { BoringThread2 t1 = new BoringThread2(); BoringThread2 t2 = new BoringThread2(); t1.start(); t2.start(); } // main } // class BoringThread2
Lärdom: En tråd körs när Java-maskinen får lust. Skriv inte trådade program som bygger på att saker ska köras i någon viss ordning. (I alla fall inte utan att synkronisera trådarna, så de garanterat körs så.)Tråd 1 har kört 1 varv i loopen. Tråd 1 har kört 2 varv i loopen. Tråd 1 har kört 3 varv i loopen. 1296 rader från tråd 1 strukna Tråd 1 har kört 1300 varv i loopen. Tråd 1 har kört 1301 varv i loopen. Tråd 1 har kört 1302 varv i loopen. Tråd 2 har kört 1 varv i loopen. Tråd 2 har kört 2 varv i loopen. Tråd 2 har kört 3 varv i loopen. Tråd 2 har kört 4 varv i loopen. Tråd 2 har kört 5 varv i loopen. Tråd 2 har kört 6 varv i loopen. Tråd 2 har kört 7 varv i loopen. Tråd 2 har kört 8 varv i loopen. Tråd 2 har kört 9 varv i loopen. Tråd 2 har kört 10 varv i loopen. Tråd 1 har kört 1303 varv i loopen. Tråd 1 har kört 1304 varv i loopen. Tråd 1 har kört 1305 varv i loopen. 4195 rader från tråd 1 strukna Tråd 1 har kört 5501 varv i loopen. Tråd 1 har kört 5502 varv i loopen. Tråd 1 har kört 5503 varv i loopen. Tråd 2 har kört 11 varv i loopen. Tråd 2 har kört 12 varv i loopen. Tråd 2 har kört 13 varv i loopen. ...
Körexempel:public class Presenter extends Thread { private String message; private double sleepTime; private int steps; public Presenter(String message, double sleepTime) { this.message = message; this.sleepTime = sleepTime; this.steps = 0; start(); } public void run() { while (true) { for (int i = 0; i < this.steps; ++i) System.out.print(" "); ++this.steps; System.out.println(this.message); try { Thread.sleep((int)(this.sleepTime * 1000)); } catch (InterruptedException e) { System.out.println("Oj! Sömnen avbruten!"); } } } // run public static void main(String[] args) { Presenter t1 = new Presenter("Turbo", 0.1); Presenter t2 = new Presenter("Svensson", 0.2); Presenter t3 = new Presenter("Skalman", 0.3); } // main } // class Presenter
Turbo Svensson Skalman Turbo Svensson Turbo Skalman Turbo Svensson Turbo Turbo Skalman Svensson Turbo Turbo Svensson Turbo Skalman Turbo Svensson Turbo Turbo Skalman Svensson Turbo Turbo Svensson Turbo Skalman Turbo Svensson Turbo Turbo Skalman Svensson Turbo Turbo Svensson Turbo Skalman ...
Det beror på att utskrifterna i två trådar kan råka komma samtidigt, och blandas med varandra.... Turbo Svensson Turbo Svensson Turbo Skalman Turbo Svensson ...
Synkronisera. En lösning:
Det finns ett "synchronized-lås" per Java-objekt. En strängliteral i ett Java-program (som "fnord") är ett enda, unikt objekt.public void run() { while (true) { synchronized ("fnord") { for (int i = 0; i < this.steps; ++i) System.out.print(" "); ++this.steps; System.out.println(this.message); } try { Thread.sleep((int)(this.sleepTime * 1000)); } catch (InterruptedException e) { System.out.println("Oj! Sömnen avbruten!"); } } } // run
Lösning: Implementera gränssnittet Runnable, som bara säger att det måste finnas en run-metod.
Filen BoringRunnable.java:
Metod:public class BoringRunnable implements Runnable { public void run() { while (true) ; } // run public static void main(String[] args) { BoringRunnable r1 = new BoringRunnable(); Thread t1 = new Thread(r1, "Tråd 1"); t1.start(); BoringRunnable r2 = new BoringRunnable(); Thread t2 = new Thread(r2, "Tråd 2"); t2.start(); } // main } // class BoringRunnable
class Buffer { private String[] queue; private int number; public Buffer (int size) { queue = new String[size]; number = 0; } // Buffer public synchronized void put(String str) { queue[number++] = str; } // put public synchronized String get() { String s = queue[0]; for (int i = 1; i < number; ++i) queue[i - 1] = queue[i]; --number; return s; } // get } // class Buffer class WriterThread extends Thread { Buffer b; public WriterThread(Buffer b) { this.b = b; } public void run() { int nrReps = 0; while (true) { String s = "Sträng nummer " + ++nrReps; System.out.println("WriterThread: Lagrar " + s); b.put(s); } } // run } // class WriterThread class ReaderThread extends Thread { Buffer b; public ReaderThread(Buffer b) { this.b = b; } public void run() { while (true) { String s = b.get(); System.out.println("ReaderThread: Hämtade " + s); } } // run } // class ReaderThread public class BufferExample { public static void main(String[] args) { Buffer b = new Buffer(100); WriterThread w = new WriterThread(b); ReaderThread r = new ReaderThread(b); w.start(); r.start(); } // main } // class BufferExample
Ur filen NotifyExample.java:
public synchronized void put(String str) { while(number == queue.length) { try { System.out.println("Buffer.put: Väntar..."); wait(); } catch (InterruptedException e) { System.out.println("Buffer.put: Oj!"); } } queue[number++] = str; notify(); } // put public synchronized String get() { while(number == 0) { try { System.out.println("Buffer.get: Väntar..."); wait(); } catch (InterruptedException e) { System.out.println("Buffer.get: Oj!"); } } String s = queue[0]; for (int i = 1; i < number; ++i) queue[i - 1] = queue[i]; --number; notify(); return s; } // get
En modell för nätverkskommunikation. Modellen har fyra nivåer, och på varje nivå kan det finnas flera olika protokoll. Ett protokoll är en samling regler för hur t. ex. kommunikation ska gå till.
Ett IP-paket innehåller IP-adressen på den dator det ska till:
Inuti IP-paketet kan man stoppa in ett data, med TCP-headrar. Headrarna innehåller till exempel numret på den port som datat ska till:
import java.net.URL; import java.net.URLConnection; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; public class ShowURL { public static void main(String[] args) { try { URL yahoo_url = new URL("http://www.yahoo.com/"); URLConnection yahoo_conn = yahoo_url.openConnection(); BufferedReader reader = new BufferedReader( new InputStreamReader( yahoo_conn.getInputStream())); String buf; while ((buf = reader.readLine()) != null) { System.out.println(buf); buf = reader.readLine(); } // while } // try catch (java.net.MalformedURLException e) { System.out.println("Fel på webbadressen"); } catch (java.io.IOException e) { System.out.println("Fel när webbsidan skulle hämtas"); } } // main } // ShowURL
Efter knapptryckning:
Filen ShowURLApplet.java:
Appleten på riktigt (om det nu fungerar i din webbläsare):import java.applet.*; import java.awt.*; import java.awt.event.*; import java.net.*; import javax.swing.*; public class ShowURLApplet extends JApplet implements ActionListener { public void actionPerformed(ActionEvent event) { this.handle_button(); } // actionPerformed private void handle_button() { try { URL yahoo_url = new URL("http://www.yahoo.com/"); getAppletContext().showDocument(yahoo_url); } // try catch (java.net.MalformedURLException e) { // Fel på webbadressen } } // handle_button public void init() { Container cp = getContentPane(); cp.setLayout(new FlowLayout()); JButton button = new JButton("Ladda YAHOO-sida"); button.addActionListener(this); cp.add(button); } // init } // ShowURLApplet
Filen Server.java:import java.net.*; import java.io.*; public class Client { public static final int PORT = 2000; public static void main(String[] args) throws IOException { InetAddress addr; if (args.length >= 1) addr = InetAddress.getByName(args[0]); else addr = InetAddress.getByName(null); Socket socket = new Socket(addr, PORT); System.out.println("Den nya socketen: " + socket); BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter( socket.getOutputStream())), true); // true: PrintWriter is line buffered BufferedReader kbd_reader = new BufferedReader( new InputStreamReader(System.in)); String buf; while (true) { buf = kbd_reader.readLine(); System.out.println("Från tangentbordet: " + buf); System.out.println("Till servern: " + buf); out.println(buf); String inline = in.readLine(); if (inline == null) break; System.out.println("Från servern: " + inline); } } // main } // Client
Körexempel, klienten:import java.io.*; import java.net.*; public class Server { public static final int PORT = 2000; public static void main(String[] args) throws IOException { ServerSocket s = new ServerSocket(PORT); System.out.println("Server-socketen: " + s); System.out.println("Servern lyssnar..."); Socket socket = s.accept(); System.out.println("Uppkoppling accepterad."); System.out.println("Den nya socketen: " + socket); BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter( socket.getOutputStream())), true); // true: PrintWriter is line buffered while (true) { String inline = in.readLine(); System.out.println("Servern tog emot: " + inline); if (inline == null || inline.equals("quit")) // Not: inline == "quit" break; out.println("Du sa '" + inline + "'"); } } // main } // Server
Körexempel, servern:bimbatron > java Client localhost Den nya socketen: Socket[addr=localhost/127.0.0.1,port=2000,localport=34029] apa Från tangentbordet: apa Till servern: apa Från servern: Du sa 'apa' morot Från tangentbordet: morot Till servern: morot Från servern: Du sa 'morot' quit Från tangentbordet: quit Till servern: quit bimbatron >
bimbatron > java Server Server-socketen: ServerSocket[addr=0.0.0.0/0.0.0.0,port=0,localport=2000] Servern lyssnar... Uppkoppling accepterad. Den nya socketen: Socket[addr=/127.0.0.1,port=34029,localport=2000] Servern tog emot: apa Servern tog emot: morot Servern tog emot: quit bimbatron >