多线程基准测试

时间:2013-01-13 20:38:29

标签: java multithreading benchmarking synchronized

我想测量2个线程计数到1000的时间。我如何对以下代码进行基准测试?

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;
    }
}

即使我使用synchronized关键字,为什么我仍然会得到以下结果(摘录)?

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

4 个答案:

答案 0 :(得分:1)

输出未同步。场景是:

  1. Thread-0单独运行9次迭代。
  2. Thread-1调用increment和getNumber,返回10
  3. Thread-0再运行三次。
  4. Thread-1使用10调用println。

答案 1 :(得分:1)

你没有同步这个:

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

因此,一个线程可以执行increment(),等待下一个线程,然后保持getValue()(从而得到你的结果)。考虑到添加值的速度有多快,更改线程会为多次迭代提供另一个时间。

待办事项     public static final String LOCK =“lock”;

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

方法不需要synchronize(正如我在评论中解释的那样)。

答案 2 :(得分:1)

  

为什么我仍然得到以下结果(摘录),即使我使用synchronized关键字?

您同步对number变量的访问权限,但是增量和获取是分开同步的,这也不会使您的println()原子。这个序列是完全可能的:

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

首先,如果您想解决“增量和获取”问题,可以使用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());
}

但是,即使这样也不能保证打印顺序。使用上面的代码,这种情况仍然可能:

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

要解决此问题,您需要使用例如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();
        }
    }
}

答案 3 :(得分:1)

你没有同步。 synchronized关键字相当于synchonize (this) {},但您增加的static数字不包含在您的对象中。你实际上有2个对象/线程,它们都与自己同步,而不是彼此同步。

要么设置属性volatile并且根本不进行同步,要么像这样使用锁定对象:

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;
    }
}