5
votes

I am new to multi-threading and While I am reading about multi threading, thought of writing this fancy multi-threading code to do the following.

My counter class is as follows.

class Counter {
  private int c = 0;

  public void increment() {
    System.out.println("increment value: "+c);
      c++;
  }

  public void decrement() {
      c--;
      System.out.println("decrement value: "+c);
  }

  public int value() {
      return c;
  }

}

This Counter object is shared between two threads. Once threads are started, I need to do the following. I want Thread2 to wait until the Thread1 increments the count of the Counter object by 1. Once this is done, Then Thread 1 informs thread2 and then Thread1 starts waiting for thread2 to decrement value by 1. Then thread2 starts and decrements value by 1 and informs thread1 again and then thread2 start waiting for thread1. Repeat this process for few times.

How can I achieve this. Many thanks in advance.

I have done the following.

public class ConcurrencyExample {

  private static Counter counter;
  private static DecrementCount t1;
  private static IncrementCount t2;

  public static void main(String[] args) {
    Counter counter = new Counter();
    Thread t1 = new Thread(new IncrementCount(counter));
    t1.start();

    Thread t2 = new Thread(new DecrementCount(counter));
    t2.start();

  }

}


public class DecrementCount implements Runnable {

  private static Counter counter;

  public DecrementCount(Counter counter) {
    this.counter = counter;
  }

  @Override
  public void run() {
    for (int i = 0; i < 1000; i++) {
      counter.decrement();     
      System.out.println("decreamented");
    }
  }

}


public class IncrementCount implements Runnable {

  private static Counter counter;

  public IncrementCount(Counter counter) {
    this.counter = counter;
  }

  @Override
  public void run() {
    for (int i = 0; i < 1000; i++) {
      counter.increment();
      System.out.println("Incremented");
    }

  }

}
4
IncrementCount should call increment(), right?Tomasz Nurkiewicz
The simplest way to do this would be to use one thread. I suggest you consider examples where using multiple threads would be faster, rather than more complicated and slower.Peter Lawrey
@TomaszNurkiewicz thanks I have fixed this.Prabash B
Why is it that the first thing everyone tries to do with threads is prevent them from serving their purpose?David Schwartz

4 Answers

3
votes

Check out Semaphore. You'll need two, one for each thread: incSemaphore and decSemaphore. In DecrementCount do:

for (int i = 0; i < 1000; i++) {
  decSemaphore.acquire();
  counter.decrement();     
  System.out.println("decreamented");
  incSemaphore.release();
}

Implement IncrementCount symmetrically. Initial value of incSemaphore should be 1 and 0 for decSemaphore.

BTW your Counter requires synchronization as well (see synchronized keyword and AtomicInteger).

0
votes

- First your increment() and decrement() must be using synchronized keyword to avoid the Race Condition See this Brian's Rule

When we write a variable which has just been read by another thread, or reading a variable which is just lately written by another thread, must be using Synchronization. And those atomic statements/Methods accessing the fields' data must be also synchronized.

- Its the JVM Thread Scheduler that has control Which thread will enter the Running State, how long its gonna stay there, and where it will go after its work has been done.

- One Cannot be sure of which thread will run first.....

- You can also use SingleThreadExecutor from java.util.concurrent, this completes one task before moving onto the second.

0
votes

Use Condition with boolean flag.

final Lock lock = new ReentrantLock();
final Condition incremented= lock.newCondition(); 
final Condition decremented= lock.newCondition(); 

Change your Counter to below

Explanation :

We have used two conditions one is incremented and one is decremented. based on boolean flag we check whether we have to wait on one condition or not.

 class Counter {
private int c = 0;
boolean increment = false;

final Lock lock = new ReentrantLock();
final Condition incremented = lock.newCondition();
final Condition decremented = lock.newCondition();

public void increment() throws InterruptedException {
    Lock lock = this.lock;
    lock.lock();
    try {
        while(increment)
            decremented.await();
        increment = true;           
        c++;
        System.out.println("increment value: " + c);
        incremented.signal();
    } finally {
        lock.unlock();
    }

}

public void decrement() throws InterruptedException {

    Lock lock = this.lock;
    lock.lock();
    try {
        while (!increment)
            incremented.await();
        c--;
        System.out.println("decrement value: " + c);
        increment = false;
        decremented.signal();
    } finally {
        lock.unlock();
    }
}

public int value() {
    Lock lock = this.lock;
    lock.lock();
    try {
        return c;
    } finally {
        lock.unlock();
    }
}

}