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

私の理解では、上記のロックと同期コード ブロックは同じ効果であるはずですが、それらを実行した結果は同じではなく、同期コードは正しく、常に 100000 ですが、ロック コードは常に正しくなく、時には 99995、99997、または他の結果ですが、100000 ではありません。

コンソール:

TaskWithLock 結果: 99991

TaskWithSync 結果: 100000

私のコードに何らかのエラーがあるはずだと思います。または、ロックに関する私の理解が間違っているか、ロックがこのように使用できません。

間違っている可能性があることを指摘してください。

4

2 に答える 2

5

lock-version では、インスタンスごとに 1 つのロックを使用しています。これは、すべてのスレッドが独自のロックを持っていることを意味し、2 つのスレッドが同じロックを使用することはないため、最終的にロックは役に立たなくなります。

これを、すべてのスレッドに対して 1 つの中央ロックに変更する必要があります。この行に static を追加します。

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 に答える