How to write a multi-threaded program in the best way

I am new to multithreading and learn about the functionality of wait, notify and notifyAll. I want the three threads to execute one after another and print the alphabets from A to Z. I tried using the code below and it seems to work as well, but I doubt this is the best way to solve the problem. Is there any other way I can make it simpler and better? Part of my code seems to be repeating.

package demo.threading;

class Flags {

    boolean flagA = true;
    boolean flagB = false;
    boolean flagC = false;

}

class Container {

    Flags flags = new Flags();
    int charVal = (int) 'A';

    void producer1() {

        try {
            while (charVal <= (int) 'Z') {
                synchronized (this) {
                    if (!flags.flagA)
                        wait();
                    else {
                        System.out.println(Thread.currentThread().getName() + " Produced : " + (char) charVal);
                        flags.flagA = false;
                        flags.flagB = true;
                        charVal++;
                        notifyAll();
                        Thread.sleep(1000);
                    }
                }
            }
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }

    }

    void producer2() {

        try {
            while (charVal <= (int) 'Z') {
                synchronized (this) {
                    if (!flags.flagB)
                        wait();
                    else {
                        System.out.println(Thread.currentThread().getName() + " Produced : " + (char) charVal);
                        flags.flagB = false;
                        flags.flagC = true;
                        charVal++;
                        notifyAll();
                        Thread.sleep(1000);
                    }
                }
            }
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }

    void producer3() {

        try {
            while (charVal <= (int) 'Z') {
                synchronized (this) {
                    if (!flags.flagC)
                        wait();
                    else {
                        System.out.println(Thread.currentThread().getName() + " Produced : " + (char) charVal);
                        flags.flagC = false;
                        flags.flagA = true;
                        charVal++;
                        notifyAll();
                        Thread.sleep(1000);
                    }
                }
            }
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }
}

public class Main {
    public static void main(String[] args) {

        Container container = new Container();

        Thread t1 = new Thread(() -> container.producer1(), "Thread 1");
        Thread t2 = new Thread(() -> container.producer2(), "Thread 2");
        Thread t3 = new Thread(() -> container.producer3(), "Thread 3");

        t1.start();
        t2.start();
        t3.start();

    }
}

The conclusion should be:

Thread 1 Produced : A
Thread 2 Produced : B
Thread 3 Produced : C
Thread 1 Produced : D
Thread 2 Produced : E
Thread 3 Produced : F
+4
source share
2 answers
package demo.thread;

public class ABCPuzzle {

    private static class RunnableImpl implements Runnable {

        private String nextThread;
        private ExecServ execServ;

        public RunnableImpl(ExecServ execServ, String nextThread) {
            this.execServ = execServ;
            this.nextThread = nextThread;
        }

        @Override
        public void run() {

            String threadName = Thread.currentThread().getName();

            synchronized (execServ) {
                try {
                    while (true) {
                        if (execServ.key > 'Z')
                            break;

                        if (threadName.equals(execServ.current)) {
                            System.out.println(threadName + " consuming "  + execServ.key);
                            Thread.sleep(1000);
                            execServ.key++;
                            execServ.current = nextThread;
                            execServ.notifyAll();
                        } else
                            execServ.wait();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static class ExecServ {
        private String current, next;
        private char key = 'A';
    }

    public static void main(String[] args) {

        ExecServ execServ = new ExecServ();
        execServ.current = "t1";

        Thread t1 = new Thread(new RunnableImpl(execServ, "t2"), "t1");
        Thread t2 = new Thread(new RunnableImpl(execServ, "t3"), "t2");
        Thread t3 = new Thread(new RunnableImpl(execServ, "t4"), "t3");
        Thread t4 = new Thread(new RunnableImpl(execServ, "t1"), "t4");

        t1.start();
        t2.start();
        t3.start();
        t4.start();

    }
}

Output:

t1 consuming A
t2 consuming B
t3 consuming C
t4 consuming D
t1 consuming E
t2 consuming F
t3 consuming G
t4 consuming H
t1 consuming I
t2 consuming J
0
source

, " ", . , Semaphore:

int numberOfThreads = 3;
Semaphore semaphore = new Semaphore(1);

for (int i = 1; i <= numberOfThreads; i++) {
    new Thread(() -> {
        try {
            semaphore.acquire();
            for (char c : "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray()) {
                System.out.println(Thread.currentThread().getName() 
                        + " produced: " + c + ".");
            }
        } catch (InterruptedException e) {
            // NOP
        } finally {
            semaphore.release();
        }
    }, "Thread " + i).start();
}

java.util.concurrent, Java 5. , Java concurrency, wait notify. , Brian Goetz "Java concurrency in Practice" .

EDIT:

public class ConcurrentAlphabet {

    private volatile Thread current;

    public static void main(String[] args) {
        new ConcurrentAlphabet().print(3,
                "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray());
    }

    public void print(int numberOfThreads, char[] alphabet) {
        Thread[] threads = new Thread[numberOfThreads];

        for (int i = 1; i <= numberOfThreads; i++) {
            int offset = i - 1;
            threads[offset] = new Thread(() -> {
                Thread me = Thread.currentThread();
                Thread next = threads[(offset + 1) % numberOfThreads];

                for (int index = offset; index < alphabet.length; index += numberOfThreads) {
                    synchronized (this) {
                        while (me != current) {
                            try {
                                wait();
                            } catch (InterruptedException e) { /* NOP */ }
                        }

                        System.out.println(me.getName(); + " produced: " + alphabet[index] + ".");
                        current = next;
                        notifyAll();
                    }
                }
            }, "Thread " + i);
        }

        current = threads[0];

        for (Thread t : threads) {
            t.start();
        }
    }

}
+4

Source: https://habr.com/ru/post/1650141/


All Articles