Concurrency Saker händer samtidigt Hur gör vi flera saker samtidigt på en dator? - Dela på en CPU - Flera CPU Flera processer på en dator. Operativsystemet (OS) tilldelar dem körtid (time slices, prioritet) Process En instans av ett program - virtual address space - kod - program counter: vilken instruktion ska köras - data (minne, register) - data (stack) - anropasstack Tråd Sekventiellt kontrollflöde i en process - program counter - data (register, stack) - anropsstack
Trådar i Java 1. Subklass till Thread, överlagra run() 2. Implementera Runnable (samma resultat, annan struktur) public class MyThread extends Thread { public MyThread(String str) { super(str); public void run() { for (int i = 0; i < 5; i++) { System.out.println(getName()+ : +i); try { sleep((long)(math.random() * 1000)); catch (InterruptedException e) { System.out.println(getName()+ : done! ); public class TwoThreadsDemo { public static void main (String[] args) { new MyThread("A").start(); new MyThread("B").start();
public class Clock implements Runnable { boolean running=true; // use flag so we can stop public void run() // we get here after start { while(running) { // get the time and convert it to a date Calendar cal = Calendar.getInstance(); Date date = cal.gettime(); // format it and display it (just println) System.out.println(date); try { Thread.sleep(200); catch (InterruptedException e) { running = false; // end while public class RunnableDemo { public static void main (String[] args) { Thread a = new Thread(new Clock(),"A").start(); Thread b = new Thread(new Clock(),"B").start(); try { Thread.sleep((long)(Math.random()*1000)); catch (InterruptedException e) { a.interrupt(); b.interrupt();
När ska man använda Thread och Runnable? Om du måste subklassa någon annan klass använd Runnable. Om det blir enklare med Thread använd den. En tråd tilldelas resurser och körtid av OS när start() anropas. En tråd får ingen körtid om den - Sover (Thread.sleep) - Väntar (Object.wait() - Object.notify()) - IO-blockerad (läs från Socket) - Avstår (Thread.yeild()) Prioritet - Preemptive (avbryter och återupptar körning av trådar, context switch) - Högst först, samma prio får samma tid - Undviker starvation att någon aldrig får körtid - Ärvs från skapande tråd - Thread.setPriority() - Thread. MAX/MIN_PRIORITY
Synkronisering Trådar kan köra samma kod samtidigt Kan ge oväntade resultat pga. delat minne Svårt att hitta fel! Exempel: public void percent(double percent) { double localvalue = this.value; localvalue = localvalue * percent / 100.0; this.value = localvalue; Value = 100 Tråd 1: Sätt till 20% av 100 = 20 Tråd 2: Sätt till 10% av 20 = 2 Möjligt scenario: Tråd 1: localvalue blir 100 Tråd 2: localvalue blir 100 Tråd 1: localvalue blir 20 Tråd 2: localvalue blir 10 Tråd 1: value blir 20 Tråd 2: value blir 10 Fel!
Lösning: synkronisera metoden public synchronized void percent(double percent) Ingen annan tråd får använda en synkroniserad metod på objektet samtidigt Synkronisering använder mycket systemresurser Synkronisera en del av en metod på vilket objekt som helst: private ArrayList<Integer> list = new ArrayList<Integer>(); public void add(int value) { if (value < 0) throw new RuntimeException( value < 0 ) synchronized (list) { list.add(value);
public class Producer extends Thread { private Box box; public Producer(Box b) { box = b; public void run() { for (int i=0; i<10; i++) { box.put(i); System.out.println("Produced "+i); try { sleep((int)(math.random() * 100)); catch (InterruptedException e) { public class Consumer extends Thread { private Box box; private String name; public Consumer(Box b, String name) { box = b; this.name = name; public void run() { int x = 0; for (int i=0; i<5; i++) { x = box.get(); System.out.println(name+ consumed +x);
public class Box { private int value; private boolean available = false; public synchronized int get() { while (available == false) { try { // wait for Producer to put value wait(); catch (InterruptedException e) { available = false; int v = value; // notify Producer that value is consumed notifyall(); return v; public synchronized void put(int v){ while (available == true) { try { // wait for Consumer to get value wait(); catch (InterruptedException e) { value = v; available = true; // notify Consumers that value has been set notifyall();
public class ProducerConsumerTest { public static void main(string[] args) { Box b = new Box(); Producer p1 = new Producer(b); Consumer c1 = new Consumer(b, A ); Consumer c2 = new Consumer(b, B ); p1.start(); c1.start(); c2.start(); Trådar som väntar - sleep() går ej att avbryta - wait() väntar på notify() - wait(long t) väntar max t millisek på notify() - notify() en tråd som väntar får köra - notifyall() alla trådar som väntar får köra
Deadlock alla trådar väntar på varandra Svårt att upptäcka så undvik! Exempel: Tråd A tar brödet Tråd B tar smöret Tråd A väntar på smöret Tråd B väntar på brödet Lösning: Tråd som misslyckas att få en resurs ger upp sin egen resurs. Låt alla trådar ta resurser i samma ordning Starvation En tråd blir alltid utan resurser. Java undviker detta till stor del.