1

Scenerio:

  1. 15個のインデックスの整数配列があります。(それぞれに何らかの値が入力されています)
  2. 2つのスレッドでインデックスの値に2(+2)を追加したいと思います。それぞれが、どのインデックスがすでに追加されているかを認識しています。
  3. 次に、スレッドに参加して終了します。

これまでのところ(私が作成したところまで)、Runnableインターフェイスを実装し、runnable内で計算される配列を提供しているだけです。私はここからこのハンドシェイクを行う方法に固執しています。助けてくれてありがとう

public class FooRunnable implements Runnable
{
    private int[] myArray = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14};

    @Override
    public void run()
    {
        for(int i=0; i<myArray.length; i++)
        {
            myArray[i] = myArray[i] +2;
            System.out.println("Thread "+Thread.currentThread().getName()+" Finished index: "+i);
            atomicCount.incrementAndGet();
        }
    }

    public static void main(String[] args)
    {
        FooRunnable r = new FooRunnable();
        Thread t1 = new Thread(r);
        Thread t2 = new Thread(r);
        t1.setName("Thread One");
        t2.setName("Thread Two");
        t1.start();
        t2.start();
    }
}

結果(目標):

プログラムが終了したとき。配列には、配列の各要素が2つの異なるスレッドを介して2ずつインクリメントされる必要があります。

4

4 に答える 4

2

これは機能しません。スレッド1がスレッド2と同時にmyArray[0]を読み取る可能性があります。次に、両方のスレッドが2を追加します。配列でAtomicIntegersを同期または使用する必要があります。これはある種の運動だと思います。何を達成したいですか?

于 2013-03-02T21:57:03.453 に答える
1

整数オブジェクトを使用して、整数アクセスを同期できます。if(myArray[i].intVal() == i)そして、スレッドが整数をインクリメントしたいときはいつでも、これがfalseを返すかどうかをチェックすることによって、その整数が以前にインクリメントされたかどうかをチェックする必要があります。その後、他のスレッドはこの整数をインクリメントしました。増分前の整数値はインデックスに等しいことに注意してください。この場合、iです。

public class FooRunnable implements Runnable
{
    private Integer[] myArray = {new Integer(0),new Integer(1),new Integer(2),new Integer(3),new Integer(4),new Integer(5),new Integer(6),new Integer(7),new Integer(8),new Integer(9),new Integer(10),new Integer(11),new Integer(12),new Integer(13),new Integer(14)};

    @Override
    public void run()
    {
        for(int i=0; i<myArray.length; i++)
        {
            synchronized(myArray[i]) {
            if(myArray[i].intVal() == i) {
            myArray[i] = myArray[i] +2;
            System.out.println("Thread "+Thread.currentThread().getName()+" Finished index: "+i); }
             }
            atomicCount.incrementAndGet();
        }
    }

    public static void main(String[] args)
    {
        FooRunnable r = new FooRunnable();
        Thread t1 = new Thread(r);
        Thread t2 = new Thread(r);
        t1.setName("Thread One");
        t2.setName("Thread Two");
        t1.start();
        t2.start();
    }
}
于 2013-03-02T22:32:24.420 に答える
1

コードはである必要がありますsynchronized。そして、これには、後続のインデックスで値をインクリメントする2つのスレッド間の適切なスレッド間通信が必要です。waitこれは、とを使用した古い方法で実現できますがnotifyjava.util.concurrentしかし今、あなたはパッケージに切り替える必要があります。コードは次のようになります。

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Foo
{
    private int[] myArray = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14};//This array can be of any length.
    private volatile int lastIndex = 0;
    private final Lock lock = new ReentrantLock(true);
    private final Condition condition = lock.newCondition();
    public void increment()
    {
        lock.lock();
        try
        {
            if (isDone())
            {
                return;
            }
            myArray[lastIndex] = myArray[lastIndex]+2;
            System.out.println("Incremented arr["+lastIndex+"] to "+myArray[lastIndex]+" via thread "+Thread.currentThread().getName());
            lastIndex++;
            condition.signal();
            if (!isDone())
            {
                condition.await();
            }
        }
        catch (Exception ex){}
        finally{lock.unlock();}
    }

    public boolean isDone()
    {
        return lastIndex == myArray.length;
    }
    public static void main(String[] args)
    {
       final Foo foo = new Foo();
       Thread th1 = new Thread("Thread1")
        {
           public void run()
            {
               while (!foo.isDone())
               {
                    foo.increment();
               }
            }
        };
        Thread th2 = new Thread("Thread2")
        {
            public void run()
            {
                while (!foo.isDone())
                {
                    foo.increment();
                }
            }
        };
        th2.start();th1.start();
    }
}
于 2013-03-02T22:37:32.550 に答える
1

そして-もちろん-アトミックを使用する他の方法があります:

public class FooRunnable implements Runnable {

    private int[] myArray = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
    // Copy myArray into my Atomic version.
    private AtomicInteger[] myAtomicArray = new AtomicInteger[myArray.length];
    {
        for(int i = 0; i < myArray.length; i++ ) {
            myAtomicArray[i] = new AtomicInteger(myArray[i]);
        }
    }

    @Override
    public void run() {
        for (int i = 0; i < myArray.length; i++) {
            myAtomicArray[i].addAndGet(2);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        FooRunnable r = new FooRunnable();
        Thread t1 = new Thread(r);
        Thread t2 = new Thread(r);
        t1.setName("Thread One");
        t2.setName("Thread Two");
        t1.start();
        t2.start();
        // Wait for them both to finish.
        t1.join();
        t2.join();
        // Print my results.
        System.out.println("Results: "+Arrays.toString(r.myAtomicArray));
    }
}

印刷する

Results: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
于 2013-03-02T23:51:47.297 に答える