0

私は配列を持っています:int [] arr = {5,4,3,1,2};

 I want to do like this::

 5 should be read by thread one
 4 should be read by thread two
 3 should be read by thread one
 1 should be read by thread two
 2 should be read by thread one

私はこの単純なプログラムを最善を尽くしました:

package com.techighost.create.deadlock;

public class ArrayReading implements Runnable {

    volatile int index = 0;

    int[] arr;

    public ArrayReading(int[] arr) {
        this.arr = arr;
    }

    @Override
    public void run() {
        synchronized (arr) {
            for (;index<=(arr.length-1);) {
                if (index % 2 == 0  && Thread.currentThread().getName().equals("Thread-One")) {
                    System.out.println(arr[index] + " " + Thread.currentThread().getName());
                    index++;
                    arr.notify();

                } else if (index % 2 != 0 && Thread.currentThread().getName().equals("Thread-Two")) {
                    System.out.println(arr[index] + " " + Thread.currentThread().getName());
                    index++;
                    arr.notify();

                }else{
                    System.out.println("In else " + Thread.currentThread().getName());
                    try {
                        arr.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        int[] arr = { 5, 4, 3, 1, 2 };
        ArrayReading arrayReading = new ArrayReading(arr);
        Thread t = new Thread(arrayReading);
        t.setName("Thread-One");
        Thread t1 = new Thread(arrayReading);
        t1.setName("Thread-Two");

        t.start();
        t1.start();

        t.join();
        t1.join();
    }
}

このスレッド名チェックはあるべきではないと思いますか?どんな体でも、このチェックを削除するために何ができるかを提案してください

4

6 に答える 6

3

@zzk.Programで言及されているように条件を使用できます。これは次のようになります

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class PrintSequentially {

private final int[] items;
private final ReentrantLock lock;
private final Condition notEven;
private final Condition notOdd;

private int currentCount = 0;

public PrintSequentially(int[] items) {
    this.items = items;
    this.lock = new ReentrantLock();
    this.notEven = lock.newCondition();
    this.notOdd = lock.newCondition();
}

public void printSeq() throws InterruptedException {

    try {
        lock.lockInterruptibly();
        while (currentCount < items.length) {
            if (currentCount % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + ":"
                        + items[currentCount++]);
                if (currentCount < items.length)
                    notEven.await();
                notOdd.signal();
            } else {
                System.out.println(Thread.currentThread().getName() + ":"
                        + items[currentCount++]);
                notEven.signal();
                if (currentCount < items.length)
                    notOdd.await();
            }
        }

    } finally {
        lock.unlock();
    }
}

}

このためのドライバープログラムは

public static void main(String[] args) {
    int arr[] ={1,2,3,4,5};
    final PrintSequentially p = new PrintSequentially(arr);

    Runnable r1 = new Runnable() {
        @Override
        public void run() {
            try {
                p.printSeq();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };

    Runnable r2 = new Runnable() {
        @Override
        public void run() {
            try {
                p.printSeq();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };

    Thread th1 = new Thread(r1);
    th1.setName("thread 1");
    th1.start();

    Thread th2 = new Thread(r2);
    th2.setName("thread 2");
    th2.start();

}

ここで、必要な数のスレッドを追加できます。順次印刷していきます。

于 2016-10-24T19:27:14.313 に答える
2

条件を使用できます。スレッド 1 は条件インデックス % 2 == 0 を待機し、スレッド 2 は条件インデックス % 2 == 1 を待機する必要があります。

条件の使用方法については、このリンクを参照してください

于 2013-02-26T21:17:14.563 に答える
1

次のようなスレッド間通信waitを使用できます。notify

class ReadNum
{
    int arr[];
    private volatile int counter = 0;
    public ReadNum()
    {
        counter = 0 ;
    }
    public ReadNum(int size)
    {
        arr = new int[size];
        for (int i = 0; i < size ; i++)
        {
            arr[i] = i;
        }
    }
    public void setArray(int[] arr)
    {
        counter = 0;
        this.arr = arr;
    }
    public synchronized void  readOdd()
    {
        while (counter < arr.length)
        {
            if (counter % 2 != 0)
            {
                System.out.println(Thread.currentThread().getName()+":->"+arr[counter]);
                counter++;
            }
            notify();
            try{
                wait();
            }catch(Exception ex){ex.printStackTrace();}
        }
        notify();//So that other EvenThread does'nt hang if OddThread completes earlier
    }
    public synchronized void  readEven()
    {
        while (counter < arr.length)
        {
            if (counter % 2 == 0)
            {
                System.out.println(Thread.currentThread().getName()+":->"+arr[counter]);
                counter++;
            }
             notify();
            try{
                wait();
            }catch(Exception ex){ex.printStackTrace();}
        }
        notify();//So that other OddThread does'nt hang if EvenThread completes earlier
    }
}
public class SequenceRead
{
    public static void main(String st[])
    {
        final ReadNum rn = new ReadNum();
        int arr[]= {1,2,34,78,99,45,4545,987,343,45};
        rn.setArray(arr);
        Thread th1 = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                rn.readEven();
            }
        },"EvenReadThread");
        Thread th2 = new Thread( new Runnable()
        {
            @Override
            public void run()
            {
                rn.readOdd();
            }
        },"OddReadThread");
        th2.start();th1.start();
    }
}

アップデート

これが、競合状態についてあなたが尋ねた説明です。

競合状態「複数のスレッドが同じリソース(通常はオブジェクトのインスタンス変数)にアクセスでき、アトミックであるはずの操作が完了する前に1つのスレッドが「競合」または「侵入」するのが速すぎると、破損したデータが生成される可能性がある状況です。したがって、プログラムの出力は、同じリソースにアクセスするさまざまなスレッドの開始、実行、および完了のシーケンスまたはタイミングに依存するため、予測できません。」

たとえば、以下のコードについて考えてみます。

class Race
{
    private int counter;
    public void printCounter()
    {
        while(counter < 100)
        {
            try
            {
                Thread.sleep(10);//Added to show Race Effect.
            }
            catch (Exception ex){}
            counter = counter + 1;
        }
        System.out.println(Thread.currentThread().getName() +" : "+counter);//If we don't consider Race condition then the Output should be 100 for all threads. 
    }
}
public class MainClasss
{
    public static void main(String st[])
    {
        final Race race = new Race();
        Thread[] th = new Thread[2];
        //Creating 2 threads to call printCounter of object race
        for (int i = 0 ; i < th.length ; i++)
        {
            th[i] = new Thread( new Runnable()
            {
                public void run()
                {
                    race.printCounter();
                }
            }, "Thread"+i);
        }
        //Starting all Threads
        for (Thread thr : th )          
        {
            thr.start();
        }
    }
}

そして、これが私が得ている出力です、それはあなたのシステムによって異なるかもしれません。

Thread1 : 100
Thread0 : 101

すべてのスレッドが期待どおりに100を印刷していません!!! なぜですか?Programは、実行中のスレッドがいつ別のスレッドにプリエンプトされるかを制御できないため、すべてJVMスレッドスケジューラに依存します。
上記の出力について考えられる説明の1つは、次のとおりです。

  1. カウンター=99で、Thread1はwhileループ内に潜入し、10ミリ秒間スリープしました。
  2. JVMスケジューラは、Thread1をThread0でプリエンプトするようになりました。
  3. Thread1は、カウンター<100を検出するため、「while」ループ内に入ります。
  4. Thread.sleepで、Thread0はThread1によってプリエンプトされます。
  5. Thread1はカウンターを1増やします。
  6. Thread1は、カウンター値を100として出力し、終了します。
  7. Thread0は実行を継続し、カウンターを1増やし、counter=101にします。
  8. Thread0は、カウンター値を101として出力し、終了します。

これは、RaceConditionのライブ展示です。
この競合状態を回避するには、ReadNumメソッドを同期化する必要があります。これにより、スレッドがそのメソッドに入ると、モニターを取得して同期化されたメソッドの所有者になります。そして、そのスレッドは、すべての操作をAtomicallyに完了した後にのみプリエンプトされます。これで、競合状態の概要がわかりやすくなることを願っています。

于 2013-02-26T21:32:09.327 に答える
1

これはおそらくある種の足を濡らすスレッドアプリケーションであることは理解していますが、最適とは言えないいくつかの問題があります。

  1. スレッドを使用することの要点は、非同期操作です。スレッドが配列内の他のすべてのエントリを処理するようにすることは、作業を分割しているように聞こえますが、同期が他のすべてを達成するため、シングルスレッドよりも遅くなる可能性があります。スレッドの性質上、「1」の前に「2」が出力されることもあります。スレッドを順番に並べるためにスレッドの速度を落とさないので、これは良いことです。

  2. あなたのコードにはいくつかの競合状態があります。たとえば、あるスレッドがリストの最後の要素を処理して移動するwait可能性がありますが、他のスレッドはすでにリストを終了しており、そのリストに到達していない可能性がありnotifyます。あなたのアプリケーションはしばしば最後にハングアップするに違いありません。

  3. Executor サービスを使用し、エントリごとにジョブを送信することを検討する必要があります。これは、ほとんどのスレッド化されたタスクを実行するための最良の方法です:

    // create a thread pool with 2 workers
    ExecutorService threadPool = Executors.newFixedThreadPool(2);
    for (int entry : arr) {
        threadPool.submit(new `(entry));
    }
    // once we have submitted all jobs to the thread pool, it should be shutdown
    threadPool.shutdown();
    // to wait for the jobs to finish you do
    threadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
    ...
    

    次に、配列全体ではなくArrayReadingエントリを取得し、それらを個別に処理できます。

  4. 最後に、他の人がすでに述べたように、boolean evenフラグを渡して、各スレッドに偶数 (true の場合) または奇数 (false の場合) のアイテムを処理させることができます。

    Thread t1 = new Thread(new ArrayReading(arr, true));
    Thread t2 = new Thread(new ArrayReading(arr, false));
    
于 2013-02-26T21:40:59.610 に答える
1

ランナブルで別のパラメーター フィールドを使用して、偶数または奇数のインデックスを読み取るように指示し、ランナブルの 2 つのインスタンス (1 つは偶数用、もう 1 つは奇数用) を作成します。ExecutorService少なくとも 2 つのスレッドで をセットアップし、ランナブルを実行します。異なるスレッドが与えられるにはあまりにも速く終了する可能性があります。これをテストしませんでした。

于 2013-02-26T21:16:15.653 に答える
0

ここにあなたが探しているコードがあります....

public class ThreadConcurrent  {
    int []array=new int[]{0,1,2,3,4,5,6,7,8,9};
    volatile int i=0;

public  void checkSum() {
    synchronized (this) {
        for(;i<array.length;){
            System.out.println("thread name "+Thread.currentThread().getName()+ "  : "+array[i]);
            i++;
            notify();
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

    }
}

public static void main(String[] args) {

    final ThreadConcurrent er=new ThreadConcurrent();       
    Thread t1=new Thread(new Runnable() {

        @Override
        public void run() {
            er.checkSum();

        }
    }, "T1");
    Thread t21=new Thread(new Runnable() {

        @Override
        public void run() {
            er.checkSum();

        }
    }, "T2");
    t1.start();
    t21.start();
}

}

于 2013-02-27T08:48:13.350 に答える