views:

110

answers:

5

I have a scenario like.... There are four threads named as Thread1, Thread2, Thread3 and Thread4. and there is one counter variable. And I want output as below

Thread1 : value of counter variable is = 0
Thread2 : value of counter variable is = 1
Thread3 : value of counter variable is = 2
Thread4 : value of counter variable is = 3

Thread1 : value of counter variable is = 4
Thread2 : value of counter variable is = 5
Thread3 : value of counter variable is = 6
Thread4 : value of counter variable is = 7

Thread1 : value of counter variable is = 8
Thread2 : value of counter variable is = 9
Thread3 : value of counter variable is = 10
Thread4 : value of counter variable is = 11

Even I have done this by logically. But I want something like, When Thread1 is printing the variable of counter then all the remaining threads should wait.....then after Thread2 should come to the picture and print the counter variable and rest should wait.

Suggest me the best solution for this. Thanks in advance :-)

+3  A: 

There is little sense in this, except for understanding synchronization. I'd use a CyclicBarrier to do this. It's a rather high level abstraction, so you don't have to use wait() or notifiy() by yourself.

Alternatively, you could use an Integer or AtomicInteger object as variable and pass it around the threads (each one should provide a consume(Integer i) method which can be called by another thread, then increments and prints the value and passes it to the next thread in the ring). In this variant, the synchronization is handled implicit within your code.

PartlyCloudy
Thanks for your suggestion. CyclicBarrier option looks good. Could you please elaborate more.(means with example)???
@partlycloudy - is it possible to use t4.t3.t2.t1.join(); ,initially create all the thread and put in wait states then use join as above.let me know.
Suresh S
CyclicBarrier won't constrain the threads to run in order, but it will at least stop one of them from running 3 times before the others get a look in.
Bill Michell
+2  A: 

I'm not sure what do you want. Do you want your threads to increment and print variable in order? It doesn't make sense, threads are independent and are running concurrently. That's what they are for.

amorfis
yes, I want to increment and print the variable in order. Yes you are right, Thread are for the concurrent run. But I want all the four threads run one by one, not concurrently.
+2  A: 

So let me get this straight: you want to use parallel processing to do serial work.

Basically what you want to do is this:

for(int i=0;i<10;i++)
    System.out.println(i);

but then with threads.

Threads are used to do things in parallel. That is what they are for. Trying to force a serial problem into this concept will not only slow down your application but also make it much more error prone.

Unless, of course, this example of yours is very much simplified. Maybe you need to give some more information for us to be able to help, then...

LeChe
A: 

This is an interesting problem, since threads are designed to work side by side independently, rather than locked into a strict order.

I think the simplest way to achieve this is with a fair ReentrantLock, an AtomicInteger and some cautious setup (to ensure that the threads start waiting on the ReentrantLock in the correct order).

Your main thread will need to initialise the counter, create the lock object and lock it, then start the four child threads in order, ensuring each of them arrives at the lock before setting the next thread off.

When all 4 threads are primed, you can release the lock and let the other threads run.

Each worker thread should grab the value from the counter, increment it, display the counter, then release the lock (which will let the next thread run) before reacquiring it.

Note that there is still a race condition here: Thread 2 could race round the loop before Thread 1 starts waiting for the lock again, and so the two threads would end up running in inverted order. To fix this, the worker threads need to wait until enough other threads are waiting until they proceed around the loop (except of course for the final iteration). Not nice, but I fear essential given the listed constraints.

This is not simple code. The lesson to be learned here, I think, is that you shouldn't really use multiple threads to perform inherently serial work! Either that, or you shouldn't care exactly which thread performs which of the serial operations.

Bill Michell
Thanks Bill for your comments. let me try with ReentrantLock, AtomicInteger to solve the problem. I have posted two ways to do it. Please check it and send me your comments.
A: 

Hello crew I have found two ways for this problem.... but still waiting for experts comments....

First way :-----

package semafore;

import java.util.concurrent.Semaphore;

public class Main { public static void main(String args[]) throws Exception { Semaphore sem = new Semaphore(1, true); Thread thrdA = new Thread(new SyncOutput(sem, "Thread1")); Thread thrdB = new Thread(new SyncOutput(sem, "Thread2")); Thread thrdC = new Thread(new SyncOutput(sem, "Thread3")); Thread thrdD = new Thread(new SyncOutput(sem, "Thread4"));

    thrdA.start();
    thrdB.start();
    thrdC.start();
    thrdD.start();

    thrdA.join();
    thrdB.join();
    thrdC.join();
    thrdD.join();

}

}

class SyncOutput implements Runnable { Semaphore sem; String msg; private static int val = 0;

SyncOutput(Semaphore s, String m) {
    sem = s;
    msg = m;
}

public void run() {
    for (int i = 0; i < 3; i++){
        try {
            sem.acquire(1);
            System.out.println(msg + " : " + ++val);
            Thread.sleep(1000);
        } catch (Exception exc) {
            System.out.println("Error Writing File");
        }
    sem.release(1);
    }
}

}

Second way :-----

package thread;

 class num {
         // state variable identifying whose turn it is.
         private String whoseTurn ="A";
         private int cnt=0;

  public  boolean writenum(String who) {

           String x = Thread.currentThread().getName();
                try{
                    Thread.sleep(1000);
                }catch(Exception e){}
          if (x.equalsIgnoreCase(whoseTurn)) {
              System.out.println(x+":"+cnt++);
              if(x.equalsIgnoreCase("A"))
                whoseTurn = "B";
              else if(x.equalsIgnoreCase("B"))
                    whoseTurn = "C";
              else if( x.equalsIgnoreCase("C"))
                    whoseTurn = "D";
              else if( x.equalsIgnoreCase("D"))
                    whoseTurn = "A";

          }
          return true; 
     }
  }


public class Game {

    public static void main(String args[]) {
        num ob = new num();
        Thread A = new Thread(new Player("A", ob));
         Thread B   = new Thread(new Player("B", ob));
        Thread C   = new Thread(new Player("C", ob));
        Thread D   = new Thread(new Player("D", ob));

    A.setName("A");
    B.setName("B");
    C.setName("C");
    D.setName("D");
   A.start();   
   B.start();  
   C.start();
   D.start();
   try {
       // Wait 5 seconds
       Thread.currentThread().sleep(5000);
   } catch (InterruptedException e) { }

   ob.writenum("DONE"); // cause the players to quit their threads.
   try {
       Thread.currentThread().sleep(100);
   } catch (InterruptedException e) { }
   }

}

class Player implements Runnable {
       num area;   // Table where they play
       String who;

       public Player(String who, num area) {
           this.area  = area;
          this.who = who;
       }

      public void run() {
      while (area.writenum(who));

      }
  }
Your first method never seems to declare val, so it won't compile. Even if you fix that, you can't guarantee that the threads will run in the same order on each pass around the loop. If a thread yields after calling release but before calling acquire, the next thread could get in and call acquire first.
Bill Michell
The second method is a bit better but you need to ensure some kind of memory barrier occurs. Simply declaring writenum to be synchronized would probably fix it, though you might want to look at the location of the sleep call in that case. Alternatively, you could declare those shared state variables volatile. You also forgot to implement the termination condition: writenum never returns false, so the threads never exit the loop.
Bill Michell