Evgenij Reznik
Evgenij Reznik

Reputation: 18614

Multithreading benchmark test

I want to measure how long it takes for the 2 threads to count till 1000. How can I make a benchmark test of the following code?

public class Main extends Thread {
    public static int number = 0;

    public static void main(String[] args) {

        Thread t1 = new Main();
        Thread t2 = new Main();

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

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

    public synchronized void increment() {
        number++;
    }

    public synchronized int getNumber() {
        return number;
    }
}

And why am I still getting the following result (extract) even though I use the synchronized keyword?

Thread-0 9
Thread-0 11
Thread-0 12
Thread-0 13
Thread-1 10

Upvotes: 2

Views: 1105

Answers (4)

fge
fge

Reputation: 121790

why am I still getting the following result (extract) even though I use the synchronized keyword?

You synchronize access to the number variable, however the increment and get are synchronized separately, and this does not make your println() atomic either. This sequence is perfectly possible:

0 -> inc
1 -> inc
0 -> getnumber
1 -> getnumber
1 -> print
0 -> print

First, if you want to solve the "increment and get" problem, you can use an AtomicInteger:

private static final AtomicInteger count = new AtomicInteger(0);

// ...

@Override
public void run()
{
    final String me = getName();

    for (int i = 0; i < 1000; i++)
        System.out.println(me + ": " + count.incrementAndGet());
}

However, even this will not guarantee printing order. With the code above, this scenario is still possible:

0 -> inc
0 -> getnumber
1 -> inc
1 -> getnumber
1 -> print
0 -> print

To solve this problem, you need to use, for instance, a ReentrantLock:

private static final Lock lock = new ReentrantLock();
private static int count;

// ...

@Override
public void run()
{
    final String me = getName;

    for (int i = 0; i < 1000; i++) {
        // ALWAYS lock() in front of a try block and unlock() in finally
        lock.lock();
        try {
            count++;
            System.out.println(me + ": " + count);
        finally {
            lock.unlock();
        }
    }
}

Upvotes: 1

SJuan76
SJuan76

Reputation: 24895

You are not synchronizing this:

    for (int i = 0; i <= 1000; i++) {
        increment();
        System.out.println(this.getName() + " " + getNumber());
    }

So, a thread can execute increment(), wait for the next thread, and after that keep with getValue() (thus getting your results). Given how fast is adding a value, changing a thread gives the other time for several iterations.

Do public static final String LOCK = "lock";

synchronized(LOCK) {
   for (int i = 0; i <= 1000; i++) {
        increment();
        System.out.println(this.getName() + " " + getNumber());
    }
}

you do not need the synchronize for the methods (as I explain in my comment).

Upvotes: 1

Nemo64
Nemo64

Reputation: 2683

You are not synchronized. The synchronized keyword is an equivalent to synchonize (this) {} but you are increasing a static number which is not contained within your object. You actually have 2 objects/threads and both of them synchronize with themself, not with each other.

Either make you property volatile and don't synchronize at all or use a lock Object like this:

public static int number = 0;
public static final Object lock = new Object();

public void increment() {
    synchronized (lock) {
        number++;
    }
}

public int getNumber() {
    synchronized (lock) {
        return number;
    }
}

Upvotes: 1

zch
zch

Reputation: 15278

Output is not synchronized. The scenario is:

  1. Thread-0 runs 9 iterations alone.
  2. Thread-1 calls increment and getNumber, which returns 10.
  3. Thread-0 runs three more iterations.
  4. Thread-1 calls println with 10.

Upvotes: 1

Related Questions