0

2つの異なるスレッドを交互に使用して奇数と偶数を印刷しようとしています。待機、通知、同期ブロックを使用して達成できましたが、待機、通知、同期を使用せずに達成できるかどうかを評価したいと思います。

以下は私が持っているコードですが、機能していません:

public class OddEvenUsingAtomic {

AtomicInteger nm = new AtomicInteger(0);
AtomicBoolean chk = new AtomicBoolean(true);

public static void main(String args[]) {
    final OddEvenUsingAtomic pc = new OddEvenUsingAtomic();

    new Thread(new Runnable() {

        @Override
        public void run() {
            while (true) {

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                if (pc.chk.compareAndSet(true, false)) {

                    System.out.println("Odd: " + pc.nm.incrementAndGet());
                }
            }

        }

    }).start();

    new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            while (true) {
                if (pc.chk.compareAndSet(false, true)) {

                    System.out.println("Even: " + pc.nm.incrementAndGet());
                }
            }

        }

    }).start();
}

}

何か案は?

ブルーノからの提案の後に別のバージョンを作成しましたが、これはうまく機能しているようです。

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

public class OddEvenUsingAtomic {

    AtomicInteger nm = new AtomicInteger(0);
    AtomicBoolean chk = new AtomicBoolean(true);

    public static void main(String args[]) {
        final OddEvenUsingAtomic pc = new OddEvenUsingAtomic();

        new Thread(new Runnable() {

            @Override
            public void run() {
                while (true) {

                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }

                    if (pc.chk.get() == Boolean.TRUE) {

                        System.out.println("Odd: " + pc.nm.incrementAndGet());
                        pc.chk.compareAndSet(true, false);
                    }
                }

            }

        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                while (true) {
                    if (pc.chk.get() == Boolean.FALSE) {

                        System.out.println("Even: " + pc.nm.incrementAndGet());
                        pc.chk.compareAndSet(false, true);
                    }
                }

            }

        }).start();
    }
}
4

3 に答える 3

3

コードが正しく同期されていない、それが問題です。

コードでは、次の実行順序が許可されています。

  1. 最初のスレッドはchk == true、ブロックを確認して設定しfalse、ブロックに入りifます。
  2. 2番目のスレッドはchk == false、ブロックを確認して設定しtrue、ブロックに入りifます。

これで、両方のブロック内に2つのスレッドがあり、次のif準備ができています。

  1. incrementAndGet()番号
  2. 印刷してください。

したがって、何が起こるかを完全に制御することはできません。

  • 任意のスレッドを呼び出すincrementAndGet()ことができるため、最初に奇数、次に偶数のスレッド「奇数」印刷を行うことができます。
  • 最初のスレッドに数値を印刷させ、ループして、条件が再び満たされることを確認できます(2番目のスレッドが再び印刷されるように設定されているため、2番目のスレッドがchk印刷trueする前にこれらすべてを印刷します)。

ご覧のとおり、目的の結果を得るには、次の操作をアトミックに実行する必要があります。

  • compareAndSet()ブール値
  • incrementAndGet()番号
  • 印刷する

3つの操作がアトミックでない場合は、可能な順序で操作を実行するようにスレッドをスケジュールすることができ、出力を制御することはできません。これを実現する最も簡単な方法は、同期ブロックを使用することです。

public static void main(final String... args) {
  final Object o = new Object();
  // ... thread 1 ...
    synchronized(o) {
      if (boolean is in the expected state) { change boolean, get number, increment, print }
    }
  // ... thread 2 ...
    synchronized(o) {
      if (boolean is in the expected state) { change boolean, get number, increment, print }
    }
}
于 2013-03-03T04:42:04.827 に答える
3

これは、待機、通知、または同期なしでオッズと偶数を出力する2つのスレッドです(少なくとも、表示されているコードでは)。

import java.util.concurrent.*;

public class ThreadSignaling {
    public static void main(String[] args) {
        BlockingQueue<Integer> evens = new LinkedBlockingQueue<>();
        BlockingQueue<Integer> odds = new LinkedBlockingQueue<>();
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        executorService.submit(() -> takeAndOfferNext(evens, odds));
        executorService.submit(() -> takeAndOfferNext(odds, evens));
        evens.offer(0);
    }

    private static void takeAndOfferNext(BlockingQueue<Integer> takeFrom,
                                         BlockingQueue<Integer> offerTo) {
        while (true) {
            try {
                int i = takeFrom.take();
                System.out.println(i);
                offerTo.offer(i + 1);
            } catch (InterruptedException e) {
                throw new IllegalStateException("Unexpected interrupt", e);
            }
        }
    }
}
于 2013-03-03T05:09:51.083 に答える
0
class MultiThreading {

    Integer counter = 0;
    Thread even;
    Thread odd;
    boolean flagEven = true;
    boolean flagOdd;

    class ThreadEven implements Runnable {
        @Override
        public void run() {
            try {
                while (counter < 100) {
                    if (flagEven) {
                        System.out.println(counter);
                        counter++;
                        flagEven = false;
                        flagOdd = true;
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    class ThreadOdd implements Runnable {
        @Override
        public void run() {
            try {
                synchronized (even) {
                    while (counter < 100) {
                        if (flagOdd) {
                            System.out.println(counter);
                            counter++;
                            flagOdd = false;
                            flagEven = true;
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void start() {
        even = new Thread(new ThreadEven());
        odd = new Thread(new ThreadOdd());
        even.start();
        odd.start();
    }

}

}

mainメソッドを呼び出す

new MultiThreading().start();
于 2017-06-22T10:32:35.570 に答える