我尝试编写一些关于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不能像这样使用。
请指出可能出现的问题。
答案 0 :(得分:5)
在lock-version中,每个实例使用一个锁。这意味着每个线程都有自己的锁,这最终导致锁无用,因为没有两个线程使用相同的锁。
您需要将此更改为所有线程的一个中央锁。向此行添加静态:
private final Lock lock = new ReentrantLock();
所以它变成了
private static final Lock lock = new ReentrantLock();
答案 1 :(得分:3)
因为您的锁对象是每个实例,并且您正在更新静态变量。所以每个Thread都有它自己的锁,使用它来保护静态变量毫无意义。