Java Concurrency: Threads, Runnables, and Synchronization

Class Acumulador

This class implements a synchronized counter.


public class Acumulador implements Comparable<Acumulador> {
    private int acumulador;
    private final int id;

    public Acumulador(int id) {
        this.id = id;
    }

    public int getAcumulador() {
        return acumulador;
    }

    public synchronized void addAcumulador(int puntuacio) {
        this.acumulador += puntuacio;
    }

    public int getId() {
        return id;
    }

    @Override
    public int compareTo(Acumulador t) {
        return t.acumulador - acumulador;
    }
}

Class Enfrontament

This class simulates a confrontation between two Acumulador objects.


public class Enfrontament extends Thread {
    private Acumulador a1;
    private Acumulador a2;

    public Enfrontament(Acumulador a1, Acumulador a2) {
        this.a1 = a1;
        this.a2 = a2;
    }

    @Override
    public void run() {
        try {
            sleep((long) (Math.random() * 2000));
            play();
        } catch (InterruptedException ex) {
            Logger.getLogger(Enfrontament.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void play() {
        int p1 = 0;
        int p2 = 0;
        for (int i = 0; i < 1000; i++) {
            if (Math.random() < 0.5) {
                p1++;
            } else {
                p2++;
            }
        }
        a1.addAcumulador(p1);
        a2.addAcumulador(p2);
    }
}

Main Method for Enfrontament


public static void main(String[] args) {
    ArrayList<Acumulador> llista = new ArrayList<>();
    for (int i = 0; i < 10; i++) {
        llista.add(new Acumulador(i));
    }

    for (int i = 0; i < llista.size() - 1; i++) {
        for (int j = i + 1; j < llista.size(); j++) {
            Enfrontament e = new Enfrontament(llista.get(i), llista.get(j));
            e.start();
        }
    }

    ThreadGroup group = Thread.currentThread().getThreadGroup();
    while (group.activeCount() > 1) {
        try {
            Thread.sleep(500);
        } catch (InterruptedException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    Object[] array = llista.toArray();
    Arrays.sort(array);

    for (int i = 0; i < array.length; i++) {
        Acumulador a = (Acumulador) array[i];
        System.out.println(i + "=" + a.getId() + ":" + a.getAcumulador());
    }
}

Class ConcurrentID

This class demonstrates concurrent execution using Thread.


public class ConcurrentID extends Thread {
    private static int count = 0;
    private int id;

    public ConcurrentID() {
        count++;
        id = count;
    }

    @Override
    public String toString() {
        return "ConcurrentID{" + id + '}';
    }

    @Override
    public void run() {
        try {
            // Here concurrent execution will begin
            sleep((long) (Math.random() * 2000));
            System.out.println("El procés " + id + " s'ha despertat");
            // Here concurrent execution ends
        } catch (InterruptedException ex) {
            Logger.getLogger(ConcurrentID.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

Class ConcurrentIDRunnable

This class demonstrates concurrent execution using Runnable.


public class ConcurrentIDRunnable implements Runnable {
    private static int count = 0;
    private int id;

    public ConcurrentIDRunnable() {
        count++;
        id = count;
    }

    public void run() {
        try {
            Thread.sleep((long) (Math.random() * 5000));
            System.out.println("El procés " + id + " s'ha despertat");
        } catch (InterruptedException ex) {
            Logger.getLogger(ConcurrentIDRunnable.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

Class ConcurrentSincronitzada

This class demonstrates synchronized access to a shared attribute.


public class ConcurrentSincronitzada extends Thread {
    private static int count = 0;
    private int id;
    private static int attCompartit = 0;

    public ConcurrentSincronitzada() {
        count++;
        id = count;
    }

    public static synchronized void update(int id) {
        attCompartit = attCompartit + 1;
        System.out.println(id + "#" + attCompartit);
    }

    @Override
    public void run() {
        try {
            sleep((long) (1000));
            update(id);
        } catch (InterruptedException ex) {
            Logger.getLogger(ConcurrentSincronitzada.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

Class Missatge

This class represents a message object used for inter-thread communication.


public class Missatge {
    private String contingut;

    public Missatge() {
        contingut = "pendent";
    }

    public String getContingut() {
        return contingut;
    }

    public void setContingut(String contingut) {
        this.contingut = contingut;
    }
}

Class Escriptor

This class writes messages to a Missatge object.


public class Escriptor extends Thread {
    private Missatge m;

    public Escriptor(Missatge m) {
        this.m = m;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                sleep((long) (Math.random() * 1000));
                synchronized (m) {
                    m.setContingut("Transferència Missatge " + i);
                    m.notifyAll();
                }
            } catch (InterruptedException ex) {
                Logger.getLogger(Escriptor.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}

Class Lector

This class reads messages from a Missatge object.


public class Lector extends Thread {
    private Missatge m;
    private int id;

    public Lector(Missatge m, int id) {
        this.m = m;
        this.id = id;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                synchronized (m) {
                    m.wait();
                    System.out.println("Lector " + id + ": " + m.getContingut());
                }
            } catch (InterruptedException ex) {
                Logger.getLogger(Lector.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}

Main Method for Cooperative Threads


public static void main(String[] args) {
    // Cooperative work of threads
    Missatge m = new Missatge();
    Escriptor e = new Escriptor(m);
    Lector l1 = new Lector(m, 1);
    Lector l2 = new Lector(m, 2);
    e.start();
    l1.start();
    l2.start();
}

Class Concurrent

This class demonstrates synchronized modification of a static accumulator.


public class Concurrent extends Thread {
    private static int acumulador;
    private int id;

    public Concurrent(int id) {
        this.id = id;
    }

    public static synchronized void modificaAcc() {
        acumulador = acumulador + 1;
        System.out.println("Procés =" + acumulador);
    }

    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            try {
                this.sleep(50);
            } catch (InterruptedException ex) {
                Logger.getLogger(Concurrent.class.getName()).log(Level.SEVERE, null, ex);
            }
            modificaAcc();
        }
    }
}

Main Method for Concurrent Class


public class Main {
    public static void main(String[] args) {
        Concurrent c1 = new Concurrent(1);
        Concurrent c2 = new Concurrent(2);
        c1.start();
        c2.start();
    }
}

Class Contenidor

This class represents a container for a message.


public class Contenidor {
    private String missatge;

    public String getMissatge() {
        return missatge;
    }

    public void setMissatge(String missatge) {
        this.missatge = missatge;
    }
}

Class Escriptor for Contenidor

This class writes messages to a Contenidor object.


public class Escriptor extends Thread {
    private Contenidor c;

    public Escriptor(Contenidor c) {
        this.c = c;
    }

    @Override
    public void run() {
        int i = 1;
        while (true) {
            try {
                double rnd = Math.random();
                rnd += 1;
                rnd *= 1000;
                Thread.sleep((long) rnd);
                synchronized (c) {
                    c.setMissatge("Missatge " + i);
                    i++;
                    c.notifyAll();
                }
            } catch (InterruptedException ex) {
                Logger.getLogger(Escriptor.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}

Class Lector for Contenidor

This class reads messages from a Contenidor object.


public class Lector extends Thread {
    private Contenidor c;
    private int id;

    public Lector(Contenidor c, int id) {
        this.c = c;
        this.id = id;
    }

    @Override
    public void run() {
        while (true) {
            try {
                synchronized (c) {
                    c.wait();
                    System.out.println("El lector " + id + ":" + c.getMissatge());
                }
            } catch (InterruptedException ex) {
                Logger.getLogger(Lector.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}

Main Method for Contenidor Example


public class Main {
    public static void main(String[] args) {
        Contenidor c = new Contenidor();
        Escriptor e = new Escriptor(c);
        Lector l1 = new Lector(c, 10);
        Lector l2 = new Lector(c, 20);
        Lector l3 = new Lector(c, 30);
        e.start();
        l1.start();
        l2.start();
        l3.start();
    }
}

Class ConcurrentRunnable

This class demonstrates a simple concurrent runnable.


public class ConcurrentRunnable extends Object implements Runnable {
    public void run() {
        while (true) {
            try {
                Thread.sleep((long) (Math.random() * 100));
            } catch (InterruptedException ex) {
                Logger.getLogger(Concurrent.class.getName()).log(Level.SEVERE, null, ex);
            }
            System.out.println("Salutació del procés Runnable");
        }
    }
}

Main Method for Concurrent and ConcurrentRunnable


public static void main(String[] args) {
    try {
        Concurrent c1 = new Concurrent(1);
        Concurrent c2 = new Concurrent(2);
        c1.setPriority(Thread.MAX_PRIORITY);
        c2.setPriority(Thread.MIN_PRIORITY);
        ConcurrentRunnable cr = new ConcurrentRunnable();
        c1.start();
        c2.start();
        // Thread th = new Thread(cr);
        // th.setDaemon(true);
        // th.start();
        Thread.sleep(2000);
        c1.setId(10);
        Thread.sleep(1000);
        c2.setId(20);
        System.out.println("El procés del main ja ha acabat");
    } catch (InterruptedException ex) {
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
    }
}