4

我尝试编写一些关于 Lock 和 synchronized 的代码并比较它们的性能差异。

代码:

public abstract class Task {
    public abstract int getTotal();
}

// Lock test class
public class TaskWithLock extends Task implements Runnable {
    private static int total = 0;
    private final Lock lock = new ReentrantLock();

    public void run() {
         try {
            lock.lock();
            doSomething();
         } finally {
            lock.unlock();
         }
    }

    private void doSomething() {
        total++;
    }

    public int getTotal() {
        return total;
    }
}

// Synchronized test class
public class TaskWithSync extends Task implements Runnable {
    private static int total = 0;
    public void run() {
        synchronized ("") {
            doSomething();
        }
    }

    private void doSomething() {
        total++;
    }

    public int getTotal() {
        return total;
    }
}

// Test class
public class Test {
    public static void main(String[] args) throws Exception {
        int count = 100000;
        runTasks(TaskWithLock.class, count);
        runTasks(TaskWithSync.class, count);
    }

    public static void runTasks(Class<? extends Runnable> clazz, int count)
        throws Exception {
        List<Thread> list = new ArrayList<Thread>(count);
        for (int i = 0; i < count; i++) {
            list.add(new Thread(clazz.newInstance()));
         }

        for (int i = 0; i < count; i++) {
            list.get(i).start();
        }

        for (int i = 0; i < count; i++) {
            list.get(i).join();
        }

        System.out.println(clazz.getSimpleName() + "Total Result: "
            + ((Task) clazz.newInstance()).getTotal());
    }
}

我的理解是上面的Lock和synchronized代码块应该是一样的效果,但是我运行的结果不一样,synchronized代码是对的,总是100000,但是lock code总是不正确,有时候是99995,或者99997,或者其他结果,但不是 100000。

安慰:

TaskWithLock 结果:99991

TaskWithSync 结果:100000

我认为我的代码应该有一些错误,或者我对 Lock 的理解是错误的,或者 Lock 不能这样使用。

请指出可能有什么问题。

4

2 回答 2

5

在锁定版本中,每个实例使用一个锁。这意味着每个线程都有自己的锁,这最终会使锁变得无用,因为没有两个线程使用相同的锁。

您需要将其更改为所有线程的一个中央锁。将静态添加到此行:

private final Lock lock = new ReentrantLock();

所以它变成了

private static final Lock lock = new ReentrantLock();
于 2013-08-29T08:04:25.570 回答
3

因为您的锁定对象是每个实例,并且您正在更新一个静态变量。所以每个线程都有自己的锁,用它来保护静态变量是毫无意义的。

于 2013-08-29T08:05:02.747 回答