5

メソッドの同期を使用して、アトミック変数 (java.util.concurrent.atomic パッケージ) と比較して、Java マルチスレッドを実験しています。

以下にクラスを示します。

// Interface ICounter.java
        public interface ICounter {
            public void increment();
            public void decrement();
            public int value();
        }

// Class Counter.java
    public class Counter implements ICounter {
        private int c = 0;

        @Override
        public void increment() {
            c++;
        }

        @Override
        public void decrement() {
            c--;
        }

        @Override
        public int value() {
            return c;
        }
    }

// Class AtomicCounter.java
    import java.util.concurrent.atomic.AtomicInteger;

    public class AtomicCounter implements ICounter {
        private AtomicInteger c = new AtomicInteger(0);

        @Override
        public void increment() {
            c.incrementAndGet();
        }

        @Override
        public void decrement() {
            c.decrementAndGet();
        }

        @Override
        public int value() {
            return c.get();
        }

        public long getIncrement() {
            return c.incrementAndGet();
        }
    }

// Class MainProg.java
    public class MainProg {
        public static void main(String args[]) {
            ICounter counter = new AtomicCounter();
                    //ICounter counter = new SynchronizedCounter();
            Thread thread1 = new Thread(new CountRunner(counter));
            Thread thread2 = new Thread(new CountRunner(counter));

            thread1.start();
            thread2.start();
        }
    }

    class CountRunner implements Runnable {
        private ICounter counter;
        public CountRunner(ICounter counter) {
            this.counter = counter;
        }

        public void run() {
            while (true) {
                counter.increment();
                System.out.println(Thread.currentThread().getName() + " count=" + counter.value());
                System.out.println("-------------------");
                try {
                    Thread.sleep(2000L);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

Atomic または Synchronized のいずれかを実行した結果は、変数 integer がスレッドセーフであることを示していません。たとえば、次のようになります。

Thread-0 count=1
-------------------
Thread-1 count=2
-------------------
Thread-0 count=3
-------------------
Thread-1 count=4
-------------------
Thread-0 count=5
-------------------
Thread-1 count=6
-------------------
Thread-0 count=7
-------------------
Thread-1 count=8
-------------------
Thread-0 count=10
-------------------
Thread-1 count=10
-------------------

結果の最後の 2 行は、2 つのスレッドがカウンター クラスの整数変数の同じ値にアクセスしていたことを示しています。おそらく私はここで何かを逃していますか?

ありがとう!

4

3 に答える 3

4

counter.increment()andSystem.out.printlnは 1 つのアトミック アクションではないためです。

Thread 1               Thread2

increment

                       increment

                       System.out.println  // print 10

System.out.println  
// print 10 too
于 2010-08-15T19:58:50.760 に答える
4

あるステップで値を増やしてから、別のステップで値を取得しています。これらの個々のステップのそれぞれは、下位クラスによってアトミックであることが保証されてAtomicIntegerいますが、2 つの別個の操作を行うという事実により、print ステートメントに表示される値は、スレッドの実行順序に左右されます。

特定のスレッドによって更新された値を正確に表示できるようにするには、更新と結果の値の取得の両方を 1 回の操作で行う必要があります。これはgetIncrement()メソッドが行います。期待される結果が得られるコードは次のようになります。

int changedValue = counter.getIncrement();
System.out.println(Thread.currentThread().getName() + " count=" + changedValue);
于 2010-08-15T20:00:03.013 に答える
2

見逃したのは、AtomicCounterクラスが正しく機能し、スレッドが と の呼び出しの間で切り替わったために、観察された動作が発生すること.increment()です.value()

-------------------
Thread-0 increment -> value = 9
-------------------
Thread-1 increment -> value = 10
-------------------
Thread-0 print value <- 10
-------------------
Thread-1 print value <- 10
-------------------
于 2010-08-15T19:58:47.313 に答える