Reputation:
I am trying to write Thread Interference Example.
Below is my code:
class Counter {
private int c = 0;
public void increment() {
c++;
}
public void decrement() {
c--;
}
public int value() {
return c;
}
}
Suppose Thread A invokes increment at about the same time Thread B invokes decrement. How to implement this one.
Upvotes: 3
Views: 225
Reputation: 42005
Now in this example if you try to execute and the output false
shows interference.
Both the Runnable
s keep a thread local count which is incremented for each invocation of increment()
and decrement()
. So after execution for some amount of time if we try to validate the values
Then you can say that:
value of Counter = invocation of increment() - invocation of decrement()
.
But when you try to verify this at the end of execution you get false
. Which shows that the actual counter value was not as expected.
public static void main(String[] args) throws InterruptedException
{
Counter c = new Counter();
IncrementingRunnable incRunnable = new IncrementingRunnable(c);
DecrementingRunnable decRunnable = new DecrementingRunnable(c);
Thread tA = new Thread(incRunnable);
Thread tB = new Thread(decRunnable);
tA.start();tB.start();
Thread.sleep(10000);
stop = true;
tA.join();
tB.join();
//verify value
int actualCount = c.c;
int expectedCount = incRunnable.count - decRunnable.count;
System.out.println(actualCount == expectedCount);
}
public static volatile boolean stop = false;
static class IncrementingRunnable implements Runnable{
volatile int count = 0;
private Counter counter;
public IncrementingRunnable(Counter c) {
this.counter = c;
}
@Override
public void run() {
while(!stop){
counter.increment();
count++;
}
}
}
static class DecrementingRunnable implements Runnable{
volatile int count = 0;
private Counter counter;
public DecrementingRunnable(Counter c) {
this.counter = c;
}
@Override
public void run() {
while(!stop){
counter.decrement();
count++;
}
}
}
Now try changing the primitive c
in Counter
to AtomicInteger
and see the output again. You will find that now the output is true
.
Upvotes: 0
Reputation: 47994
To get two threads to start executing at the same time you can use a latch. (Which is to say, two threads that become available for execution as close together as possible.) Still for a single increment/decrement each it will probably take many runs to observe an interference. For a repeatable experiment you probably want to call increment/decrement several times in parallel and observe the final value of c.
final Counter counter = new Counter()
final CountDownLatch latch = new CountDownLatch(1);
Thread thread1 = new Thread(new Runnable() {
public void run() {
latch.await();
for (int i = 0; i < 100; i++) {
counter.increment();
}
}}).start():
Thread thread2 = new Thread(new Runnable() {
public void run() {
latch.await();
for (int i = 0; i < 100; i++) {
counter.decrement();
}
}}).start():
Thread.sleep(10);//give thread 2 a timeslice to hit the await
latch.countDown();
System.out.println(counter.value()); //non-zero value indicates interference
Upvotes: 1
Reputation: 136162
There is not guarantee how they will run it depends on OS scheduler. There is nothing better than this
Thread a = new ThreadA();
Thread b = new ThreadB();
a.start();
b.start();
Upvotes: 2