Klasser som datastrukturer Ex: du vill skicka ett meddelande som består av text (String), avsändarnamn (String), klockslag (två int). Du kan förstås skicka alla dessa efter varandra. Bättre är att bygga ett paket som innehåller dem.
Anger vad ett meddelande är class Message implements Serializable { String text; String sender; int hour; int minute; och hur det konstrueras Message(String thetext, String thesender, int thehour, int theminute) { text = thetext; sender = thesender; hour = thehour; minute = theminute;
ObjectOutputStream output; ObjectInputStream input; För att skicka ett meddelande på output: output.writeobject(new Message("Hej", "Emil", 12, 22)); För att ta emot ett meddelande på input: Message message = (Message)input.readObject(); message.text innehåller nu meddelandetexten, message.sender innehåller nu avsändaren, etc
Magi eller teknik? Vid test: det verkar som om denna aldrig utförs Kommer hit men aldrig hit!
Pontus: Ändra den ordning som strömmarna skapas i. Det bara är så. Magi!
RTFM Read the f-ing manual
Ur dokumentationen Alltså, teknik och inte magi!
Trådar Horstmann kap 20 http://download.oracle.com/javase/tutorial/essential/concurrency/procthread.html Ett sätt att få ett program att göra flera saker samtidigt. Olika aktiviteter körs parallellt.
Varför trådar? 1. Prestanda. En modern CPU har flera kärnor och varje kärna kan köra en tråd. En del kärnor kan köra mer än en tråd.
Varför trådar? 2. Reaktivitet. En del av programmet behöver vänta, tex på inmatning. Då kan andra delar ändå fortsätta.
Varför trådar? 3. Modularitet. En del program struktureras naturligast som en samling parallella aktiviteter
Exekveringsmodell Minnesarea Programtext xxxxxxxxxxxxxx xxxxxxxxx xxxxxx xxxxx xxxxxxxxxxx xxxxxxxxxxxxxx xxxxxxx xxxxx xx xxxxxxxxx xxxxxxxx xxxxxx xxxx xxxxxxxx xxxxxx xxxxxxx xxxxxx xxxxxxxx xxxxxxxxx xxxx xxxxxxxx xxxxxxx xxxxxx xxxx xxxxx xxxxxx xxxxxxxxx xxxxx xxxxx xxxx
Fler trådar: Vi har flera pilar som vandrar samtidigt i programmet
Exekveringsmodell Minnesarea Programtext xxxxxxxxxxxxxx xxxxxxxxx xxxxxx xxxxx xxxxxxxxxxx xxxxxxxxxxxxxx xxxxxxx xxxxx xx xxxxxxxxx xxxxxxxx xxxxxx xxxx xxxxxxxx xxxxxx xxxxxxx xxxxxx xxxxxxxx xxxxxxxxx xxxx xxxxxxxx xxxxxxx xxxxxx xxxx xxxxx xxxxxx xxxxxxxxx xxxxx xxxxx xxxx
Skapa tråd main-tråden finns automatiskt i programstart Det finns en klass Thread. När man instansierar den får man en ny tråd. Man skriver alltså tex Thread t = new Thread (...) så får man en ny tråd som refereras av t. Dessutom måste man ange var den ska börja arbeta. Det gör man när man anropar konstruktorn.
Thread - Konstruktorn tar ett argument: ett objekt av typ Runnable Runnable är ett interface. För att implementera det måste klassen ha en metod public void run () class A implements Runnable { public void run () { Här kommer trådar att starta Thread t = new Thread(new A()); Skapar en ny tråd. Den står i startgroparna vid det nygjorda A-objektets metod run()
Starta trådar För att starta en tråd t anropa dess metod start() Thread t = new Thread(new A()); t.start(); Här måste A implementera Runnable Här startar tråden med As metod run() Börjar köra vid det nygjorda A-objektets metod run() Efter detta är två trådar aktiva: 1.Den gamla tråden som fortsätter med programmet efter t.start() 2. Den nya som börjar vid run() i A-objektet
Exempel Gör en server som lyssnar på två portar samtidigt. Hur ska det gå till? När man lyssnar på en port (med accept()) väntar man ju tills något anrop kommer.
Exempel: lyssna samtidigt på portar 12345 och 12346 public class Main { public static void main(string[] args) { new Receiver(12345); new Receiver(12346); Receiver int port = 12345 class Receiver { int port; Socket socket; ServerSocket serversocket; Receiver (int p) { port = p; try { serversocket = new ServerSocket(port); socket = serversocket.accept();... Skapas två receivers? Inget mer händer förrän någon client anropar på port 12345. Receivern för port 12346 skapas inte förrän konstruktorn kört klart.
public class Main { public static void main(string[] args) { Thread t1 = new Thread(new Receiver(12345)); t1.start(); Thread t2 = new Thread(new Receiver(12346)); t2.start() class Receiver implements Runnable { int port; Socket socket; ServerSocket serversocket; Receiver (int p) { port = p; Receiver-konstruktorn kommer nu bara ihåg portnumret Receiver Här skapas två Receivers och en tråd per Receiver. Trådarna startas. int port = 12345 Receiver int port = 12346 public void run() { try { serversocket = new ServerSocket(port); socket = serversocket.accept(); Metoden run() gör allt det som... konstruktorn brukade göra
Två olika sätt att skapa trådar: Det vi pratat om class A implements Runnable { public void run() { Skriv här det som ska göras Ett alternativt sätt class A extends Thread { public void run() { Skriv här det som ska göras new Thread(new A()).start(); new A().start()
Exempel
Exempel på använding av StreamManager istället för readobject(): registrera sig som lyssnare och skriv metoden objectreceived()
Stor fallgrop: race Trådars relativa hastighet är inte förutsägbar. Nondeterminism: Det finns flera olika möjligheter att fortsätta programmet, eftersom flera olika pilar kan flytta Om flera trådar försöker bearbeta samma data samtidigt är resultatet oförutsägbart. Kallas race. Undvik bäst genom att ge trådarna separata data som inte påverkar varandra. Låt dem inte anropa swing samtidigt.
Exempel på race class MainClass { int x = 0; class A implements Runnable { public void run() { x = 1; class B implements Runnable { public void run() { x = 2; public static void main(string[] args) { new Thread(new A()).start(); new Thread(new B()).start(); Vad är x när trådarna kört klart?
Exempel på race class MainClass { int x = 0; class A implements Runnable { public void run() { x = x + 1; public static void main(string[] args) { new Thread(new A()).start(); new Thread(new A()).start(); Vad är x när trådarna kört klart?
Exempel på race MainClass int x = 01 2 class MainClass { int x = 0; class A implements Runnable { public void run() { x = x + 1; public static void main(string[] args) { new Thread(new A()).start(); new Thread(new A()).start(); Vad är x när trådarna kört klart?
Exempel på race MainClass int x = 01 class MainClass { int x = 0; class A implements Runnable { public void run() { x = x + 1; Högerledet = 1 Högerledet = 1 public static void main(string[] args) { new Thread(new A()).start(); new Thread(new A()).start(); Vad är x när trådarna kört klart?
Undvik race Antingen genom att se till att olika trådar inte delar några data Eller genom att låsa data så att bara en tråd åt gången kan använda det
Lås Finns många slags. Ett enkelt: För metoder som deklareras synchronized garanterar Java att bara en tråd åt gången släpps in till objektet, tex void synchronized f() { Ordet fungerar som en vaktpost vid ett objekt, och släpper bara in en pil åt gången. Kommer flera pilar får de vänta tills objektet blir ledigt.
Lås För kommandon som deklareras synchronized garanterar Java att bara en tråd åt gången släpps in, tex synchronized (lock) { Ett låsobjekt. Kan vara vilket objekt som helst. Om en tråd kommer dit och låset är upptaget får tråden vänta....
Stor fallgrop: deadlock Två trådar kan låsa varandra. Kallas deadlock. Uppstår om tråd 1 ska köra a som anropar b och tråd 2 ska köra b som anropar a, och både a och b är synchronized. Var försiktig! (Deadlock avoidance, detection och recovery behandlas i operativsystemskurser.) synchronized (a) {... synchronized(b) {... synchronized (b) {... synchronized(a) {...
Swing-tråden Swing har en speciell tråd som används för alla callbacks. Så tex musklick, timeravbrott etc hanteras av en speciell tråd.
Swing-tråden Fallgrop 1: Swing-tråden hamnar i race eller deadlock med main-tråden Vanlig lösning: avsluta maintråden när GUI är färdigbyggt!
Swing-tråden Fallgrop 2: Swing-tråden sövs, tex gör en read() eller en lång loop eller hamnar i ett deadlock Vanlig lösning: en callback gör bara minsta möjliga arbete. Ska något mer invecklat utföras så skapa en ny tråd för det. (Obs dock att du då kan få ett race med den tråden!)
Swing är inte trådsäkert Om flera trådar anropar Swing samtidigt är resultatet oförutsägbart. public void actionperformed(actionevent e) { vänta på input från egen användare... display(newmessage); public void objectreceived(int i, Object message, Exception e) { vänta på input från andra partnern... Kan ske samtidigt display(newmessage); av olika trådar? private void display(string message) { myjtextarea.append(message);
Bara en tråd åt gången får anropa Swing Object swinglock = new Object(); private void display(string message) { synchronized(swinglock) { myjtextarea.append(message);
Overloading Vi kan ha flera olika metoder med samma namn Dessa måste i så fall skiljas genom olika signaturer: parametrarnas typ och antal int sum (int n1, int n2) { Exempel return n1+n2; int sum(int n1, int n2, int n3) { return n1+n2+n3;
int sum (int n1, int n2) { return n1+n2; int sum(int n1, int n2, int n3) { return n1+n2+n3; Rätt overloadvariant sum(2,7); bestäms av signaturen: Anropar denna parametrarnas antal och typ sum(3,5,9); Anropar denna
Overload vs Polymorfi Overload: Olika programkod hanterar olika parametertyper Polymorfi: Samma programkod hanterar olika parametertyper Java tillåter overload och kan göra viss polymorfi med hjälp av interface
Overloading exempel Likartade uppgifter på olika parametertyper (tex println())
Overloading exempel Defaultvärden för parametrar (tex JFrame())
Tumregler Se upp när du använder en metod i något bibliotek att du verkligen använder rätt overloadvariant. Undvik att skriva egna overloaded metoder. Det förvirrar mest.
Klasshierarkier Sanningen bakom extends Ett ovärdeligt sätt att strukturera stora program Ganska ovärt för små program
Biblioteksanvändning: Subklassning Ex: gör en egen variant av JFrame, med extra metoder class Biljard extends JFrame {... Biljard () { setlayout(...);... Vi kan använda och definiera om alla metoder i JFrame
extends Givet en klass A kan vi definiera en underklass B med ordet extends i klasshuvudet. Underklassens objekt ärver då allt från överklassen: class A { int x; void f(int z) {... class B extends A { int y;... b = new B(); if (b.x == b.y)... c = b.f(0);
class A class B extends A p y g f z h p g f new B() h y z
extends = specialisering Exempel class Ball {... metoder för att rita, flytta, krocka etc class CueBall extends Ball {... metoder för att skjuta iväg bollen
Klasshierarkier En underklass kan i sig användas som överklass till en ännu mer specialiserad klass: class Business {... class RetailBusiness extends Business {... class KMart extends RetailBusiness {... Här ärver KMart både från RetailBusiness och Business
class A class B extends A class C extends B p y q g z v f h p g f new C() h y z q v
Business RetailBusiness ServiceBusiness KMart Macys Kinkos Single inheritance: Varje klass har bara en omedelbar överklass som den ärver från. (Java har single inheritance. Tex Python och C++ har multiple inheritance). Arv går i flera led. Om inget sägs är den speciella klassen Object överklass.
Overriding Om en metod som finns i överklassen definieras om i underklassen gäller definitionen i underklassen. Detta kallas overriding. class A { int x; void f(int z) {... class B extends A { int y; void f(int z) {... c = b.f(0);
class A class B extends A p h g f z h p g f new B() h z
Exempel JPanel definierar en metod paintcomponent(). Alla underklasser till JPanel ärver denna. Skriver vi ingen ny sådan metod i underklassen så finns den ursprungliga (som ritar en tom yta). Vi kan göra en override och definiera en egen paintcomponent() som innehåller önskad grafik
super Om man definierat om en metod i underklassen men ändå vill använda överklassens metod, använd super. class A { int x; void f(int z) {... class B extends A { int y; void f(int z) {... void g() { y = f(0); y = super.f(0);
Exempel class A extends JPanel { override void paintcomponent(graphics g) { super.paintcomponent(g)...
Konstruktorer I underklassens konstruktor lägger Java alltid automatiskt in ett anrop till överklassens konstruktor först. class A { int z; A() { z = 0; class B extends A { int y; B() { y = 1; b = new B(); Här har b.z värdet 0 och b.y värdet 1 eftersom både As och Bs konstruktorer har använts
super() Om man vill får man i underklassens konstruktor göra ett anrop till överklassens konstruktor med notationen super(). Detta måste då ligga först i konstruktorn. Vanlig användning: för att använda rätt overloadvariant av överklassens konstruktor
Exempel Utan super() Med super() class A extends JFrame { A() {... class A extends JFrame { A() { super( Titel );... Inget explicit anrop till JFrames konstruktor. Då sker automatiskt ett anrop till JFrame(), dvs det skapas ett fönster utan titel Ett anrop till JFrames konstruktor med parametern Titel. Detta innebär ett anrop till JFrame( Titel ), dvs det skapas ett fönster med rubriken Titel.