0

I am trying to print odd and even numbers using 2 different threads alternately. I was able to achieve it using wait, notify and synchronize block but now i want to evaluate if we can achieve it without using wait, notify and synchronize.

Following is the code i have but its not working:

public class OddEvenUsingAtomic {

AtomicInteger nm = new AtomicInteger(0);
AtomicBoolean chk = new AtomicBoolean(true);

public static void main(String args[]) {
    final OddEvenUsingAtomic pc = new OddEvenUsingAtomic();

    new Thread(new Runnable() {

        @Override
        public void run() {
            while (true) {

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

                if (pc.chk.compareAndSet(true, false)) {

                    System.out.println("Odd: " + pc.nm.incrementAndGet());
                }
            }

        }

    }).start();

    new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            while (true) {
                if (pc.chk.compareAndSet(false, true)) {

                    System.out.println("Even: " + pc.nm.incrementAndGet());
                }
            }

        }

    }).start();
}

}

Any ideas?

I created another version after suggestions from Bruno which seems to be working better:

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

public class OddEvenUsingAtomic {

    AtomicInteger nm = new AtomicInteger(0);
    AtomicBoolean chk = new AtomicBoolean(true);

    public static void main(String args[]) {
        final OddEvenUsingAtomic pc = new OddEvenUsingAtomic();

        new Thread(new Runnable() {

            @Override
            public void run() {
                while (true) {

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

                    if (pc.chk.get() == Boolean.TRUE) {

                        System.out.println("Odd: " + pc.nm.incrementAndGet());
                        pc.chk.compareAndSet(true, false);
                    }
                }

            }

        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                while (true) {
                    if (pc.chk.get() == Boolean.FALSE) {

                        System.out.println("Even: " + pc.nm.incrementAndGet());
                        pc.chk.compareAndSet(false, true);
                    }
                }

            }

        }).start();
    }
}
Lokesh
  • 7,810
  • 6
  • 48
  • 78
  • 1
    What exactly do you mean by "it is not working"? What results are you getting? Did you try to run your code in a debugger, or with some additional logging enabled? – Bruno Reis Mar 03 '13 at 04:26
  • With above code i want one thread to print only even numbers and other thread to print only odd numbers. I want to achieve it just with Atomic Integer and its not happening. Threads are mixing up the odd even values. – Lokesh Mar 03 '13 at 04:29
  • 1
    *"Threads are mixing up the odd even values."* - please describe what is happening **clearly**. "Mixing up" is not a clear description. – Stephen C Mar 03 '13 at 04:35
  • Following is a sample output, you can see odd numbers in front of even numbers this is waht i am calling mixing up : Odd: 1 Even: 2 Odd: 3 Even: 4 Even: 6 Odd: 5 Odd: 7 Even: 8 Even: 10 Odd: 9 Odd: 11 Even: 12 Odd: 13 Even: 14 Even: 16 Odd: 15 Odd: 17 Even: 18 Even: 19 Odd: 20 Even: 22 Odd: 21 Odd: 23 Even: 24 Odd: 25 Even: 26 Odd: 27 Even: 28 – Lokesh Mar 03 '13 at 04:36

3 Answers3

3

The code is not correctly synchronized, that's the problem.

The following execution order is allowed in your code:

  1. First thread sees chk == true, sets it to false and enters the if block.
  2. Second thread sees chk == false, sets it to true and enters the if block.

Now, you have 2 threads both inside their if blocks, getting ready to:

  1. incrementAndGet() the number
  2. Print it.

Therefore, you have absolutely no control on what is going to happen.

  • You can have any of the threads call incrementAndGet(), therefore you can have thread "Odd" printing, first, an odd number, and later, an even number.
  • You can have the first thread print the number, loop, see that the condition is satisfied again (since the second thread has set chk to true again, print, all of this before the second thread had the chance to print).

As you can see, to achieve the result you want, you must have the following operations done atomically:

  • compareAndSet() the boolean
  • incrementAndGet() the number
  • print it

If the 3 operations are not atomic, then you can have the threads being scheduled to run the operations in any possible order, you have no control on the output. The easiest way to achieve this is to use a synchronized block:

public static void main(final String... args) {
  final Object o = new Object();
  // ... thread 1 ...
    synchronized(o) {
      if (boolean is in the expected state) { change boolean, get number, increment, print }
    }
  // ... thread 2 ...
    synchronized(o) {
      if (boolean is in the expected state) { change boolean, get number, increment, print }
    }
}
Bruno Reis
  • 37,201
  • 11
  • 119
  • 156
  • Perfect, this shld work... i have edited by code and seems to be working. Just one thing change boolean shld come after increment. Do you agree? Also if we move change boolean to after increment , then do we need synchronization? I dont think so – Lokesh Mar 03 '13 at 04:53
  • Your edit makes my answer completely invalid for those who read the new version of the question. I really think you should revert your edit, leave your first wrong version, and ADD your new, correct version in the end of your question, preferably after something clearly stating that you added that as an edit, after you got some answers. After that, I will comment on your new input and on your new version, and how it relates to what I answered. There's some etiquette around here. – Bruno Reis Mar 03 '13 at 04:55
  • Added the new version below the first version and apologies for earlier error. I am wondering if we really need synchronization. – Lokesh Mar 03 '13 at 05:02
  • Yes, you do need synchronization, since, as I explained, you need the have the operations been executed **atomically**. One way to ensure the set of operations is atomic is to use a `synchronized` block (which is, by far, the most common solution and most simple to read and maintain). Another way is to do what you did: it is a "non-standard" method to achieve synchronization, in this case completely equivalent (even in memory visibility aspects). In any case, I cannot see any reason other than "I want to try something completely different to study a bit" to do what you did in the 2nd version. – Bruno Reis Mar 03 '13 at 05:05
  • From Wikipedia: *Thread synchronization or serialization, strictly defined, is the application of particular mechanisms to ensure that two concurrently-executing threads or processes do not execute specific portions of a program at the same time*. You used one particular mechanism. I used a different one -- the standard. – Bruno Reis Mar 03 '13 at 05:07
  • Oh, and some extra info: you can use a `boolean` and an `int` instead of `AtomicBoolean` and `AtomicInteger` if you use `synchronized`. If you don't want to use `synchronized`, you can use your 2nd version with a `volatile boolean` and a `volatile int` instead of the `Atomic*` classes. All of these options achieve the same thing, and are all correct. – Bruno Reis Mar 03 '13 at 05:11
  • You are right , i was trying to just study if this can be achieved without locking. Volatiles should do the job here. – Lokesh Mar 03 '13 at 05:50
  • Lokesh, one more thing: if you are trying to avoid locking because you've heard that "locking is evil" (ie, it makes things slow, etc), that kind of information is very, *very* old. Using "synchronized" in Java nowadays is very good. For instance, it won't lock right away if it can't obtain the lock, but it will loop and retry some times before giving up. Also uncontended locking is *very* fast. Anyways, it is very good to exercise the kind of thing you asked about. – Bruno Reis Mar 03 '13 at 06:02
3

Here are two threads printing odds and evens with no wait, notify, or synchronized (at least not in the code you can see):

import java.util.concurrent.*;

public class ThreadSignaling {
    public static void main(String[] args) {
        BlockingQueue<Integer> evens = new LinkedBlockingQueue<>();
        BlockingQueue<Integer> odds = new LinkedBlockingQueue<>();
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        executorService.submit(() -> takeAndOfferNext(evens, odds));
        executorService.submit(() -> takeAndOfferNext(odds, evens));
        evens.offer(0);
    }

    private static void takeAndOfferNext(BlockingQueue<Integer> takeFrom,
                                         BlockingQueue<Integer> offerTo) {
        while (true) {
            try {
                int i = takeFrom.take();
                System.out.println(i);
                offerTo.offer(i + 1);
            } catch (InterruptedException e) {
                throw new IllegalStateException("Unexpected interrupt", e);
            }
        }
    }
}
Ryan Stewart
  • 126,015
  • 21
  • 180
  • 199
0
class MultiThreading {

    Integer counter = 0;
    Thread even;
    Thread odd;
    boolean flagEven = true;
    boolean flagOdd;

    class ThreadEven implements Runnable {
        @Override
        public void run() {
            try {
                while (counter < 100) {
                    if (flagEven) {
                        System.out.println(counter);
                        counter++;
                        flagEven = false;
                        flagOdd = true;
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    class ThreadOdd implements Runnable {
        @Override
        public void run() {
            try {
                synchronized (even) {
                    while (counter < 100) {
                        if (flagOdd) {
                            System.out.println(counter);
                            counter++;
                            flagOdd = false;
                            flagEven = true;
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void start() {
        even = new Thread(new ThreadEven());
        odd = new Thread(new ThreadOdd());
        even.start();
        odd.start();
    }

}

}

call in the main method

new MultiThreading().start();
Shailendra Yadav
  • 1,822
  • 1
  • 12
  • 16