Prajwal Krishna
Prajwal Krishna

Reputation: 21

Print a sequence of numbers using threads without any synchronization

I am trying to write a simple code to print numbers in sequence. Scenario is like

1
2
3
4
5
.. and so on 

here is the code I have written

public class CounterThread implements Runnable {
    int counterNumber;

    public CounterThread(int counterNumber) {
        this.counterNumber = counterNumber;
    }

    @Override
    public void run() {
        System.out.println(this.counterNumber);
    }


    public static void main(String[] args) throws InterruptedException {
        int number = Integer.parseInt(args[0]);
        Thread[] listOfThreads = new Thread[number];
        for(int i = 1; i <= number; i++){
            CounterThread counterThread = new CounterThread(i);
            Thread thread = new Thread(counterThread);
            thread.start();
            listOfThreads[i-1] = thread;
        }

        for(Thread thread : listOfThreads){
            thread.join();
        }
    }
}
        

I realize that this is a very bad coding practice for thread programming, but i am still at a novice level trying to understand how threads behave when synchronized and when not. The output is jumbled which is to be expected but not what is required. i am not sure where i am going wrong, any help is much appreciated.

Upvotes: 2

Views: 988

Answers (2)

Mustafa Poya
Mustafa Poya

Reputation: 3027

you can just call the join() after the start() because the start of method in first loop cause it to execute and before reaching to the next loop it already did its work, so you need to call it in first loop after start to make sure its ending before starting the next one:

the join() method which allows one thread to wait until another thread completes its execution. If t is a Thread object whose thread is currently executing, then t.join() will make sure that t is terminated before the next instruction is executed by the program.

public class CounterThread implements Runnable {
    int counterNumber;

    public CounterThread(int counterNumber) {
        this.counterNumber = counterNumber;
    }

    @Override
    public void run() {
        System.out.println(this.counterNumber);
    }

    public static void main(String[] args) throws InterruptedException {
        int number = Integer.parseInt(args[0]);;
        for (int i = 1; i <= number; i++) {
            CounterThread counterThread = new CounterThread(i);
            Thread thread = new Thread(counterThread);
            thread.start();
            thread.join();
        }
    }
}

Upvotes: 1

Steyrix
Steyrix

Reputation: 3226

You can optimize your code by writing this, it will simply make the main thread wait for the current thread to complete its execution.

for (int i = 1; i <= number; i++) {
    CounterThread counterThread = new CounterThread(i);
    Thread thread = new Thread(counterThread);
    thread.start();
    thread.join();
}

However, it is a really strange piece of code. In such cases, where you are not allowed to use synchronized in multithreaded environment, the best you can go with is using volatile keyword or atomic variables. Both approaches are designed to make all the writes and reads to the variable atomic.

volatile int number = 1; 

...

@Override
public void run() {
    System.out.println(number++);
}

... 

for (int i = 1; i <= number; i++) {
    CounterThread counterThread = new CounterThread();
    Thread thread = new Thread(counterThread);
    thread.start();
}

But you should note, that volatile does not give 100% guarantee that you will avoid race condition. Especially in this case, since number++ will not be an atomic operation. It will be actually number = number + 1 - one read and one write.

But with Atomic, incrementing will be an atomic operation and you can write something like

AtomicInteger number = new AtomicInteger(0);

...

@Override
public void run() {
    System.out.println(number.incrementAndGet());
}

Upvotes: 3

Related Questions