2

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

4 に答える 4

1

出力が同期されていません。シナリオは次のとおりです。

  1. スレッド 0 は 9 回の反復を単独で実行します。
  2. スレッド 1 は、increment と getNumber を呼び出します10
  3. Thread-0 は、さらに 3 回の反復を実行します。
  4. スレッド 1 は println を で呼び出します10
于 2013-01-13T20:45:46.323 に答える
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(コメントで説明しているように)。

于 2013-01-13T20:47:00.613 に答える
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();
        }
    }
}
于 2013-01-13T20:48:05.653 に答える
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;
    }
}
于 2013-01-13T20:49:02.930 に答える