0

I am new to Threading and I'm trying to make Output look like: aAbBcCdDeE... . I searched and tried a lot of stuff but nothing really made it work. In the Exercise you are supposed to do it with a global boolean variable but I didn't really find anything useful and am kinda lost. I appreciate the help!

public class ABCThread implements Runnable {
    char c;

    public ABCThread(char c) {
        this.c = c;
    }

    @Override
    public synchronized void run() {

        for (char i = 0; i < 26; i++) {
            System.out.println(c++);
            try {
                Thread.sleep(500);

            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }

    public static void main(String[] args) throws InterruptedException {

        Thread t1 = new Thread(new ABCThread('a'));
        Thread t2 = new Thread(new ABCThread('A'));

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

    }

}

Output:

a
A
B
b
C
c
d
D
e
E
f
F
G
g
H
h
I
i
J
j
Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
44ly
  • 5
  • 3
  • You need some form of synchronization between the two threads, otherwise how would they know when to run and when to wait? Using a boolean is one option. – assylias Aug 12 '21 at 16:16
  • 2
    I understand this is an assignment, but it's a stupid one. The best tool for this job (or anything that requires alternation of tasks in perfect lockstep) is a single thread. Also global variables are terrible too. – erickson Aug 12 '21 at 16:32

7 Answers7

0

Quick answer:

You can't force a thread to run at a certain moment. What you can do though is let those two run "out of sync" (not related to async coding).

Thread t1 = new Thread(new ABCThread('a'));
Thread.sleep(250);
Thread t2 = new Thread(new ABCThread('A'));

The 1st thread will print about every 500 ms and the 2nd thread will print at 250, 750, 1250, etc. Note that this would not be a correct way to solve this in real programs. But then again, you would also likely not add Thread.sleep(500) to the run method.

Better:

You need synchronization between the threads. Because you start two threads you can use a boolean.

public class ABCThread implements Runnable {
char c;
static boolean synchronizer = false;
boolean runOn;

public ABCThread(char c, boolean runOn) {
    this.c = c;
    this.runOn = runOn;
}

@Override
public synchronized void run() {
    int count = 0;
    while(count < 26)
    {
        if(runOn != synchronizer) 
        {
           Thread.sleep(100);
           continue;
        }
        count++;
        synchronizer = !synchronizer;
        System.out.println(c++);
        
    }

}

    Thread t1 = new Thread(new ABCThread('a', false));
    Thread t2 = new Thread(new ABCThread('A', true));

Just typing this out. It might not compile. Thread.sleep(100) is just some number. It could possibly be lower, but doesn't matter much for the question.

Even better The previous code can run with only 2 threads! 1 will just stay stuck with synchronizer = false. If you add a third then the synchronizer won't work because it only has 2 states. You could add an integer instead of the boolean and another integer amountOfThreads. The amountOfThreads will need to be set to the amount of threads you will start up. Then increase the atomic integer when the thread prints and if the synchronizer (the atomic int) is more than amountOfThreads, set it to 0.

Ole Pannier
  • 3,208
  • 9
  • 22
  • 33
Marco
  • 54
  • 2
0

You're supposed to use a boolean to control which thread prints:

  1. Thread 1 waits for the boolean to be false. Then it prints and sets it true.
  2. Thread 2 waits for the boolean to be true. Then it prints and sets it false.

In this way, the threads will alternate. Also, all of this will be much faster if you use signaling between threads instead of sleep:

import java.util.*;
import java.lang.*;
import java.io.*;

public class ABCThread implements Runnable {
    static Object monitor = new Object();
    static boolean turn = false;
    
    char c;
    final boolean myTurn;

    public ABCThread(char c, boolean myTurn) {
        this.c = c;
        this.myTurn = myTurn;
    }

    @Override
    public void run() {

        for (char i = 0; i < 26; i++) {
            synchronized(monitor) {
                while (turn != myTurn) {
                    try {
                        // Note that the lock is release while I'm waiting,
                        // So the other thread can claim it here.
                        monitor.wait();
                    } catch (Exception e) {
                    }
                }
                System.out.println(c++);
                turn = !myTurn;
                monitor.notifyAll();
            }
        }

    }

    public static void main(String[] args) throws InterruptedException {

        Thread t1 = new Thread(new ABCThread('a', false));
        Thread t2 = new Thread(new ABCThread('A', true));

        t1.start();
        t2.start();
        t1.join();
        t2.join();

    }
}
Matt Timmermans
  • 53,709
  • 3
  • 46
  • 87
  • Hey, I'm pretty sure it's a dumb question but why does the program not work if monitor and turn are not static? – 44ly Aug 17 '21 at 14:17
  • If they are not static, then each thread has their own separate copy of those variables.. Each thread will wait for the other thread to change their copy of turn and notify their copy of monitor, but that will never happen, because the other thread is doing that to the other copy. – Matt Timmermans Aug 17 '21 at 17:44
0

What you need? A "shared resource" between threads.

Further: A synchronous FSM (Finite state machine)

Below is code that demonstrated how to achieve that.

public class Main
{
    // The shared resource
    public static class State {
        
        private int val;
        private int nStates;

        // Init value and number of states.
        public State(int init, int nStates) {
            this.val = init;
            this.nStates = nStates;
        }
        
        int get() {
            return val;
        }
        // Define how to get to next state. For simple use case, just increase then modulo it. eg: 0, 1, 0, 1
        // Avoid modulo in-case you need very very high performance.
        void next() {
            this.val = (this.val + 1) % nStates;
        }
    }
    
    public static class ABCThread implements Runnable{
        private char c;
        private State s;
        private int type;
        public ABCThread(char c, State s, int type) {
            this.c = c;
            this.s = s;
            this.type = type;
        }

        @Override
        public void run() {
            try {
            for (char i = 0; i < 26; i++) {
                // Do things synchronously
                synchronized(s){
                    while(s.get() != type) {
                        // Wait for our turn.
                        s.wait();
                    }
                    System.out.print(c++);
                    // Update state
                    s.next();
                    // Notify to other threads to do their job.
                    s.notifyAll();
                }
            }
            }catch(Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {

        // Define the state.
        State s = new State(0, 2);


        /* Uncomment this block to have 3 synchronous threads. Will print aA1bB2...
        s = new State(0, 3);
        Thread t3 = new Thread(new ABCThread('1', s, 2));
        t3.start();
        t3.join();
        */
        Thread t1 = new Thread(new ABCThread('a', s, 0));
        Thread t2 = new Thread(new ABCThread('A', s, 1));


        // Start threads
        t1.start();
        t2.start();
        // Wait for these threads to finish before exit.
        t1.join();
        t2.join();
    }
}
Liem Le
  • 581
  • 7
  • 17
0

Here is the one of the solution to solve the given problem. It uses wait to wait the current thread after printing one letter and notify the other thread to print its letter, and same cycle repeats. The concept of Thread wait and notify is very well explained here.

Short description:

To wait or notify any thread, it (invoking thread) must acquire the lock on any common object. In below example, each thread is acquiring the lock on this (self) (via synchronized run method) to wait and on opponent to notify it (the another thread).

public class App implements Runnable {
    char c;
    App opponent;
    boolean go;

    public App(char c, boolean go) {
        this.c = c;
        this.go = go;
    }

    public void setOpponent(App opponent) {
        this.opponent = opponent;
    }

    public static void main(String[] args) {
        App a = new App('a', true);
        App b = new App('A', false);

        Thread t1 = new Thread(a);
        Thread t2 = new Thread(b);

        a.setOpponent(b);
        b.setOpponent(a);

        t1.start();
        t2.start();
    }

    @Override
    public synchronized void run() {
        for (char i = 0; i < 26; i++) {

            try {
                if (go) {
                    System.out.println(c++);
                    this.wait();
                    synchronized (opponent) {
                        opponent.notify();
                    }
                } else {
                    System.out.println(c++);
                    synchronized (opponent) {
                        opponent.notify();
                    }
                    this.wait();
                }

            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

Here is the more simplified and understandable version of above code. In this code, both the threads are acquiring lock on same lock object, printing the letter, going in WAIT state (so release the lock) and giving turn to other BLOCKED thread waiting for the lock on lock. The other thread then acquires the lock on lock, prints the letter, notifies the previous thread which was waiting on lock object, and goes into WAIT condition, thus releasing the lock.

public class App2 implements Runnable {
    char c;
    Object lock;
    boolean go;

    public App2(char c, boolean go) {
        this.c = c;
        this.go = go;
    }

    public void setLock(Object lock) {
        this.lock = lock;
    }

    public static void main(String[] args) {
        App2 a = new App2('a', true);
        App2 b = new App2('A', false);

        Thread t1 = new Thread(a);
        Thread t2 = new Thread(b);

        Object lock = new Object();

        a.setLock(lock);
        b.setLock(lock);

        t1.start();
        t2.start();
    }

    @Override
    public void run() {

        for (char i = 0; i < 26; i++) {
            synchronized (lock) {
                try {
                    if (go) {
                    
                        System.out.println(c++);
                        lock.wait();
                        lock.notify();
                    
                    } else {
                    
                        System.out.println(c++);
                        lock.notify();
                        lock.wait();
                    
                    }
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}

UPDATE:

Above two approaches will work in most of the cases, but will not guarantee that t1 will be executed before t2 every time. Though t1 is started before t2, but it does not mean that thread scheduler will always pick t1 to execute before t2. To be sure that t1 will execute before t2 in every case, we need to ensure that t2 gets started once t1 is in RUNNABLE state (i.e. running). Below is the one of the way of how we can achieve it:

public class App3 implements Runnable {
    char c;
    App3 opponent;
    boolean go;
    boolean createOpponent = false;

    public App3(char c, boolean go) {
        this.c = c;
        this.go = go;
    }

    public void setOpponent(App3 opponent) {
        this.opponent = opponent;
    }

    public void setCreateOpponent(boolean createOpponent) {
        this.createOpponent = createOpponent;
    }

    public static void main(String[] args) {
        App3 a = new App3('a', true);
        App3 b = new App3('A', false);

        Thread t1 = new Thread(a);

        a.setOpponent(b);
        a.setCreateOpponent(true);

        b.setOpponent(a);

        t1.start();
    }

    @Override
    public synchronized void run() {
        if (createOpponent) {
            setCreateOpponent(false);
            new Thread(opponent).start();
        }
        for (char i = 0; i < 26; i++) {

            try {
                if (go) {
                    System.out.println(c++);
                    this.wait();
                    synchronized (opponent) {
                        opponent.notify();
                    }
                } else {
                    System.out.println(c++);
                    synchronized (opponent) {
                        opponent.notify();
                    }
                    this.wait();
                }

            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}
Jignesh M. Khatri
  • 1,407
  • 1
  • 14
  • 22
  • First of All thank you so much for this answer, I really appreciate it a lot. I hope I got how it works: The synchronized oponent variable lets a Thread wait if another Thread is already using it (just like join does). So the Thread t1 goes into the first if statement and prints out c and then goes into wait state while the Thread t2 goes into the else statement, also prints c and then notifys t1 and goes into wait state and then both go into the next for loop? So basicly t1 is always a bit faster than t2 because they execute at the same time but t2 has the longer path? – 44ly Aug 13 '21 at 22:16
  • Can't this lead to mistakes because Threads are inconsistent? Or did I get something wrong? Sorry if it's a dumb question and thank you so much for the time you put into your answer! – 44ly Aug 13 '21 at 22:17
  • I am impressed with how you are debugging this concept. You are somewhat correct that it may lead to inconsistencies (not always, it depends on the thread schedular) in the above two approaches. Check my updated answer, it will guarantee that `t1` is executed before `t2` in every case. – Jignesh M. Khatri Aug 14 '21 at 08:49
  • Can I imagine it like this: If you just start 2 Threads one after another the thread you started first is starting a bit earlier than the 2nd one but the 'time difference' is smaller than the potential inconsistency (and that's what happenes in my code on the top). But your programs, especially the updated version, give some buffer between the 2 Threads and that buffer is bigger than the potential inconsistency which makes it consistent. Thread 2 is always gonna be slower because Thread 1 creates and starts it (With slower I mean that Thread 1 is further advanced in the run function than T1 is – 44ly Aug 14 '21 at 11:43
  • No your imagination is not correct. When you start 2 threads one after the other, they will be submitted to the tread scheduler. Now its up to the thread scheduler to run whichever thread first. In most of the cases, thread scheduler will run first submitted thread first, but not in every case. In my updated version, I have created and ran 2nd thread from 1st thread itself, thus I am assured that 1st thread is running and then only 2nd thread will come into existence. It will just delay the 2nd thread a bit, but once both are in execution, they will run in sync (with `wait` and `notify`). – Jignesh M. Khatri Aug 14 '21 at 13:25
  • The code which you have written in question contains 2 mistakes: 1) You have assumed that `t1` will always run before `t2`, but this is wrong assumption. 2) You have entered delay of `500ms` via `Thread.sleep`, but you never know how much exact delay is needed to make both the treads sync. It totally depends on the processor. It may work on some processor, but not on other. In my code, I haven't entered any delay. But using `wait` and `notify` to run threads in sync. In this case I am not worried about how much delay is needed. They will work in sync by waiting and notifying the other. – Jignesh M. Khatri Aug 14 '21 at 13:35
  • I expressed myself pretty badly, I was talking about the first Output but because the run method is synchronized at the time when t1 creates t2, t2 can't use the run Method yet because it's already in use, correct?. I think I understood the concept itself now and just have to code it a couple times to get it into my brain. I can't express how much I appreciate the time you put into your answer, it really helped a lot! (and sorry for the late answer) – 44ly Aug 16 '21 at 15:43
  • Glad it helped. Just remember that `synchronized` always works upon any object. Means threads will compete to access the `synchronized` object. You cannot sync the threads, but need to make them access common `synchronized` object, to make them run in sync. – Jignesh M. Khatri Aug 17 '21 at 04:49
0

Hope this helps...

public class ABCThread implements Runnable {
    char c;
    boolean flag;

    public ABCThread(char c, boolean flag) {
        this.c = c;
        this.flag = flag;
    }

    @Override
    public synchronized void run() {
        for (char i = 0; i < 52; i++) {
            try {
                if (flag) {
                    System.out.println(c++);
                    notifyAll();
                    flag = false;
                    wait(100);
                } else {
                    flag = true;
                    wait(100);
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    public static void main(String[] args) throws InterruptedException {

        Thread t1 = new Thread(new ABCThread('a', true));
        Thread t2 = new Thread(new ABCThread('A', false));

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

    }
}

or you can define separate methods for printing small and capital letters and run them in two separate threads

public class ABCThread {

    boolean flag;

    public ABCThread(boolean flag) {
        this.flag = flag;
    }

    public static void main(String[] args) throws InterruptedException {

        ABCThread abc = new ABCThread(false);

        Thread t1 = new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    abc.printSmallLetters();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });
        Thread t2 = new Thread(new Runnable() {
            public void run() {
                try {
                    abc.printCapitalLetters();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

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

    }

    synchronized void printSmallLetters() throws InterruptedException {
        for (char i = 'a'; i < 'z'; i++) {
            while (flag == true) {
                wait();
            }
            System.out.println(i);
            notifyAll();
            flag = true;
        }
    }

    synchronized void printCapitalLetters() throws InterruptedException {
        for (char i = 'A'; i < 'Z'; i++) {
            while (flag == false) {
                wait();
            }
            System.out.println(i);
            notifyAll();
            flag = false;
        }
    }
}

-1

output

just replace the println by print to get a series output like this other than that everything seems to be fine, you can see the output i got in the screenshot above

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • What I meant is that I want the first Thread to print out the first char and the right after the second Thread his first char. What happens right now is that sometimes the first Thread starts first and sometimes the second One so the Output can be something like : aABb but I always want it to be aAbB – 44ly Aug 12 '21 at 16:11
-2

No way. The order of execution of threads cannot be controlled).You can use Thread.yield(). But yield () - tries to tell the scheduler to execute the next thread, but it stays in the RUNNABLE state.

Jeka_FRI
  • 71
  • 1
  • 9
  • Well it's an uni exercise and I don't think it's supposed to be that hard because we just started with Threads. It wants us to solve it with a global boolean variable so maybe that makes it easier? – 44ly Aug 12 '21 at 16:21
  • maybe they want you to know about atomic variables – Jeka_FRI Aug 12 '21 at 16:24
  • similar https://stackoverflow.com/questions/52949210/printing-alphabets-and-numbers-using-multi-threading – Jeka_FRI Aug 12 '21 at 16:27