Java锁定使用"私人最终锁定"和同步结果不一样

时间:2013-08-29 07:59:09

标签: java multithreading locking synchronized

我尝试编写一些关于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和同步代码块应该是一样的效果,但是我运行它们的结果不一样,同步代码是对的,它总是100000,但锁码总是不正确的,有时是99995,或者99997,或其他结果,但不是100000。

控制台:

TaskWithLock结果:99991

TaskWithSync结果:100000

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

请指出可能出现的问题。

2 个答案:

答案 0 :(得分:5)

在lock-version中,每个实例使用一个锁。这意味着每个线程都有自己的锁,这最终导致锁无用,因为没有两个线程使用相同的锁。

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

private final Lock lock = new ReentrantLock();

所以它变成了

private static final Lock lock = new ReentrantLock();

答案 1 :(得分:3)

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