Variables changed by one thread are not seen by other thread

I have created 5 threads T1,T2..T5. T1 sets threadId and count to 2.

Subsequently, T2 should proceed as the loop while(!(Thread.currentThread().getName().equals(threadId.toString()))) should fail.

However for T2 , threadId remains 1 and hence its also waiting.

Please let me know what am I missing here.

public class Main {
    public static void main(String args[])
    {
        int noOfthreads = 5;
        Thread [] t = new Thread[noOfthreads];
        for(int i = 0; i<noOfthreads ; i++) {
            OddEven oe = new OddEven(15, noOfthreads);
            t[i] = new Thread(new Runnable() {
                
                @Override
                public void run() {
                    try {
                        oe.printNumbers();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    };
                    
                }
            });
        }
        for(int i = 0; i<noOfthreads ; i++) {
            t[i].setName(String.valueOf(i+1));
            t[i].start();
            System.out.println("started thread " + (i+1));
        }
        
        for(int i=0; i<noOfthreads; i++) {
            try {
                t[i].join();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}


public class OddEven {
int max ; 
int count;
volatile Integer threadId;
int noOfThreads ;


public OddEven(int max, int noOfThreads) {
    super();
    this.max = max;
    this.noOfThreads = noOfThreads;
    count = 1 ;
    threadId =1;
}

//TODO: Try to pass threadId as a parameeter here
public synchronized void printNumbers() throws InterruptedException
{

       while(count <= max)
       {
           while(!(Thread.currentThread().getName().equals(threadId.toString()))) 
           {
               wait();
           }
           System.out.println("thread " + Thread.currentThread().getName() + "printed" + count) ;
           count++;
           threadId = (threadId + 1)%noOfThreads;
           notifyAll();
       }
}

}

Answer

The changes are not seen by each other because there is no shared state between threads. Each thread has its own OddEven instance, so only T1 proceeds to skip the call to wait() (its threadId is already 1) and terminates. T2 (and the rest) never go past the wait() call because no one is going to change the threadId field of their OddEven instance.

First thing you can do is move the instantiation of OddEven outside of the for loop where you create the threads: this way every thread will use the same OddEven instance.

When you do that, you’ll notice that the first 4 threads will go past their first call to wait() (and then they will be stuck at their second wait() call), while thread5 will remain stuck at its first wait() call: this is because threadId never goes to 5, it walks the [0..4] range (cause you had threadId % 5). To fix this just name your threads from 0, or fix the modulo operation.

When you do that, the program will actually terminate. But you’ll notice that you will have printed 5 more times (the number of thread) over max. This is because the count <= max condition is checked “before” a thread will do its increment. I don’t know what you want to achieve/observe so I cannot advise more on this.

The code for what I’ve explained above, so you can try it yourself:

public class Main {
public static void main(String args[])
{
    int noOfthreads = 5;
    Thread [] t = new Thread[noOfthreads];
    OddEven oe = new OddEven(15, noOfthreads);
    for(int i = 0; i<noOfthreads ; i++) {
       t[i] = new Thread(new Runnable() {
            
            @Override
            public void run() {
                try {
                    oe.printNumbers();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                };
                
            }
        });
    }
    for(int i = 0; i<noOfthreads ; i++) {
        t[i].setName(String.valueOf(i));
        t[i].start();
        System.out.println("started thread " + (i));
    }
    
    for(int i=0; i<noOfthreads; i++) {
        try {
            t[i].join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

private static class OddEven {
    int max ;
    int count;
    volatile Integer threadId;
    int noOfThreads ;


    public OddEven(int max, int noOfThreads) {
        super();
        this.max = max;
        this.noOfThreads = noOfThreads;
        count = 1 ;
        threadId = 0;
    }

    public synchronized void printNumbers() throws InterruptedException
    {

        while(count <= max)
        {
            while(!(Thread.currentThread().getName().equals(threadId.toString())))
            {
                wait();
            }
            System.out.println("thread " + Thread.currentThread().getName() + " printed " + count) ;
            count++;
            threadId = (threadId + 1)%noOfThreads;
            System.out.println("thread " + Thread.currentThread().getName() + " nextThreadId " + threadId) ;
            notifyAll();
        }
    }
}

}