0

Javaでマルチスレッドを使用する方法を学ぼうとしています。メインと、スレッド A と B を拡張する 2 つのクラスがあります。メインで A を開始し、B を複数回呼び出します。A が終了したら、B からメインに何かを送信します。

メインは、A と B の 2 つのスレッドを作成し、両方のスレッドを開始します。A が何かを実行すると、結果が B に渡されます。メインは B からの回答を収集し、別のことを実行します。B からメインに合計を戻す方法がわかりません。

また、2 つのクラス (スレッド) をインスタンス化する方法もわかりませんが、Java は値渡しを使用するため、A に B の参照を与えます。誰かが私にいくつかの指針を与えることができますか?

public static void main(String[] args)
{
    B b = new B();
    A a = new A(100, b);

    B.start();
    A.start();

    A.join(); // Waiting for A to die

    // Here I want to get a total from B, but I'm not sure how to go about doing that

}


public class A extends Thread
{
    private int start;
    // Some reference to B
    B b;
    public A (int n, B b) {
        int start = n;
        this.b = b;
    }

    public void run() {
        for (int i = 0; i < n; i++) {
            b.add(i);
        }
    }
}

public class B extends Thread
{
    private int total;

    public B () {
        total = 0;
    }

    public void add(int i) {
        total += i;
    }
}
4

5 に答える 5

5

あなたのサンプルコードを、より意味のある例と思われるものに変更しました。

スレッド間の通信は通常、共有データ (またはパイプ、ソケットなどのチャネル - しかし、そこには行きません...) を介して処理されます。この共有データをスレッド クラス内に含めることはまったく問題ありませんが、スレッドの管理に使用するデータ/メソッドから共有データを分離しました。

これが、スレッドとデータ オブジェクトの関係を理解するのに役立つことを願っています。

public class TestThreads {
    public static void main(String[] args)
    {
        DataShare ds = new DataShare();
        B b = new B(ds);
        A a = new A(100, ds);

        b.start();
        a.start();

        try {
            a.join(); // Waiting for A to die
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println ("Accumulated total from B = " + b.getTotal());      
        b.endThread();
    }   
}


public class DataShare {
    private int value;

    public DataShare () {
        value = -1;
    }

    public synchronized boolean setValue(int val) {
        boolean valueSet = false;
        if (value == -1) {
            value = val;
            valueSet = true;
        }
        return valueSet;        
    }

    public synchronized int getValue() {
        int val = value;
        value = -1;
        return val;
    }    
}


public class A extends Thread {
    private int max;
    private DataShare dataShare;

    public A (int n, DataShare ds) {
        max = n;
        dataShare = ds;
    }

    public void run() {
        int i = 0;
        while (i < max) {
            if (dataShare.setValue(i)) {
                i++;
            }
        }
    }
}


public class B extends Thread {
    private int total;
    private DataShare dataShare;
    private boolean running = false;

    public B (DataShare ds) {
        dataShare = ds;
        total = 0;
    }

    public void run() {
        running = true;
        while (running) {
            int nextValue = dataShare.getValue();
            if (nextValue != -1) {
                total += nextValue;
            }
        }
    }

    public int getTotal() {
        return total;
    }

    public synchronized void endThread() {
        running = false;
    }
}

値が設定/読み取られるのを待っている間、両方のスレッドが貴重なサイクルを浪費しているため、この素朴な例は最適とはほど遠いことを認識しています。私が作ろうとしているポイントに対処しながら、例をできるだけ単純にしたかっただけです。

于 2013-07-30T13:26:14.243 に答える
0

main メソッドで作成した 2 つのスレッド間の通信を実現しようとしていると思います。しかし、これは起こっていません。私はあなたのコードにいくつかの変更を加え、それを以下に含めて、あなたが何をしたいのかを示しました。

まず、あなたの例のいくつかの修正:

main メソッドのようにスレッド オブジェクトを参照する場合、クラス名 (A および B) を使用することはできません。代わりにオブジェクト名を使用してください (a および b)。

クラス A コンストラクターでは、メンバー変数を参照する代わりに、新しいローカル変数startを作成しています。したがってint start = nstart = n

コンストラクターで設定された回数をループしたいと思います。したがってfor (int i = 0; i < n; i++) {for (int i = 0; i < start; i++) {

参照/値による受け渡しは、ここではあまり関係ありません。オブジェクト参照は、他のものと同様に値によって渡されます。ただし、興味深いのは参照変数 (オブジェクト アドレス) の内容であり、変更されることはありません。つまり、オブジェクト参照をメソッドに渡すと、メソッドはその特定のオブジェクトに対処し、オブジェクトの内容に加えられた変更はメソッドの外部でも表示されます。

あなたが意図したと思うように、いくつかの修正を加えた例を次に示します。

public class TestThreads {
        public static void main(String[] args)
        {
            B b = new B();
            A a = new A(100, b);

            b.start();
            a.start();

            try {
                a.join(); // Waiting for A to die
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            // Getting a total from b is simple, if you provide the method for it
                System.out.println ("Accumulated total from B = " + b.getTotal());      
        }

}


public class A extends Thread {
    private int start;
    // Some reference to B
    B b;
    public A (int n, B b) {
        start = n;
        this.b = b;
    }

    public void run() {
        for (int i = 0; i < start; i++) {
            b.add(i);
        }
    }
}


public class B extends Thread {
    private int total;

    public B () {
        total = 0;
    }

    public void add(int i) {
        total += i;
    }

    public int getTotal() {
        return total;
    }
}

さて、これらの例の問題は次のとおりです。

オブジェクトはスレッドではなく、その逆も同様です。メイン スレッド (スレッド tM と呼びます) では、クラス B のオブジェクトを作成し、その run() メソッドで開始する新しいスレッド (スレッド tB) をフォークしています。ただし、run メソッドをオーバーライドしなかったため、脅威は作成後すぐに終了します。

次に、クラス A のオブジェクトを作成します。オブジェクト b (スレッド tB とは関係ありません) への参照を与え、新しいスレッド (スレッド tA) をフォークします。ここでは、run() メソッドを実装しました。結果は次のとおりです。

スレッド tM は最初の作業を行い、スレッド tA が終了するのを待っています。スレッド tB が開始され、その直後に終了しました。スレッド tA は、オブジェクト a のカウンターをインクリメントし、オブジェクト b にカウンターをその合計に追加させるすべての作業を行っています。

tA が 100 インクリメント後に終了すると、tM が起動し、オブジェクト b から合計を取得します (これもスレッド tB とは関係ありません)。

于 2013-07-30T11:35:40.513 に答える
0

まともなやり方。クラス Aのインスタンスを渡すだけです。

public class Foo {
   public void doFoo() {..} // that's the method you want to use
}

public class Bar {
   private Foo foo;
   public Bar(Foo foo) {
      this.foo = foo;
   }

   public void doSomething() {
      foo.doFoo(); // here you are using it.
   }
}

そして、次のことができます。

Foo foo = new Foo();
Bar bar = new Bar(foo);
bar.doSomething();
于 2013-07-30T06:53:27.553 に答える