3

2つの独立したスレッドの実行をインターリーブしようとしています。両方に10回の反復を伴うrunメソッドがあり、反復ごとにスレッドをコンテキストスイッチしたいように。

スレッドAが開始し、印刷などを実行した後、スレッドBに制御が渡されます。次にスレッドBが印刷し、制御をAに戻し、両方が終了するまで続きます。

これを行うための効果的なメカニズムは何ですか?

サンプルコードを添付しています。あなたが助けることができることを願っています。

// Suspending and resuming a thread for Java 2

class NewThread implements Runnable {
  String name; // name of thread
  Thread t;
 // boolean suspendFlag;

  NewThread(String threadname) {
    name = threadname;
    t = new Thread(this, name);
    System.out.println("New thread: " + t);
  //  suspendFlag = false;
    t.start(); // Start the thread
  }
  public String getState()
  {
    Thread t=Thread.currentThread();

    return t.getState().toString(); 
  }
  // This is the entry point for thread.
  public void run() {
    try {
      for(int i = 15; i > 0; i--) {
        System.out.println(name + ": " + i);
        Thread.sleep(200);
        synchronized(this) {
            //SuspendResume.suspendFlag2=false;
            SuspendResume.suspendFlag1=true;
          while(SuspendResume.suspendFlag1) {
            wait();
            //System.out.println(SuspendResume.ob1.t.getState().toString());
           // if(SuspendResume.ob2.t.getState().toString()=="WAITING")
            //  SuspendResume.ob2.t.notify();
          }
        }
      }
    } catch (InterruptedException e) {
      System.out.println(name + " interrupted.");
    }
    System.out.println(name + " exiting.");
  }

  void mysuspend() {
 //   suspendFlag = true;
  }

  synchronized void myresume() {
   // suspendFlag = false;
    notify();
  }
}
class NewThread2 implements Runnable {
      String name; // name of thread
      Thread t;
     // boolean suspendFlag;

      NewThread2(String threadname) {
        name = threadname;
        t = new Thread(this, name);
        System.out.println("New thread: " + t);
      //  suspendFlag = false;
        t.start(); // Start the thread
      }
      public String getState()
      {
        Thread t=Thread.currentThread();

        return t.getState().toString(); 
      }
      // This is the entry point for thread.
      public void run() {
        try {
          for(int i = 15; i > 0; i--) {
            System.out.println(name + ": " + i);
            Thread.sleep(1000);
            synchronized(this) {
                //SuspendResume.suspendFlag1=false;
                //while(SuspendResume.suspendFlag1) {
         //     while(suspendFlag) {
                //wait();
                //System.out.println(SuspendResume.ob2.t.getState().toString());
                //if(SuspendResume.ob1.t.getState().toString()=="WAITING")
                //SuspendResume.ob1.t.notify();
              //}
                SuspendResume.suspendFlag1=false;
                notify();
            }
          }
        } catch (InterruptedException e) {
          System.out.println(name + " interrupted.");
        }
        System.out.println(name + " exiting.");
      }

      void mysuspend() {
     //   suspendFlag = true;
      }

      synchronized void myresume() {
       // suspendFlag = false;
        notify();
      }
    }
class SuspendResume {
     static boolean suspendFlag1=false;
    static NewThread ob1 = new NewThread("One");
    static NewThread2 ob2 = new NewThread2("Two");

   // static boolean suspendFlag2=false;

  public static void main(String args[]) {


    try {
      //Thread.sleep(1000);
      //ob1.mysuspend();
      //System.out.println("Suspending thread One");
      //Thread.sleep(1000);
      //ob1.myresume();
      //System.out.println("Resuming thread One");
     // ob2.mysuspend();
      //System.out.println("Suspending thread Two");
      Thread.sleep(1000);
     // ob2.myresume();
      //System.out.println("Resuming thread Two");
    } catch (InterruptedException e) {
      System.out.println("Main thread Interrupted");
    }

    // wait for threads to finish
    try {
      System.out.println("Waiting for threads to finish.");
      System.out.println(ob1.getState());
      System.out.println(ob1.getState());
      ob1.t.join();
      ob2.t.join();
    } catch (InterruptedException e) {
      System.out.println("Main thread Interrupted");
    }

    System.out.println("Main thread exiting.");
  }
}
4

4 に答える 4

2

まず、2つのスレッドを連続して何度も実行したいというシナリオがどのようなものかわかりません。これは、ループ内で2つの異なるメソッドを実行している単一のスレッドのように聞こえます。それでも、それは面白い挑戦のように聞こえるので、私はそれを取り上げました。

Java 5のExchangerクラスを利用すると、ソリューションはかなり小さくなります。最終的にRunnableクラスが1つになりました。それらの2つのインスタンスを使用して、ブール値trueとブール値falseを相互に渡します。Exchangerクラスは、スレッドセーフな方法でブール値の受け渡しを容易にします。Runnableは、ブール値のtrue値を持っている場合にのみコードを実行します。

package interleavedexample;

import java.util.concurrent.Exchanger;
import java.util.logging.Logger;

/**
 *
 */
public class InterleavedRunnable implements Runnable {

  private final String name;

  private final Exchanger<Boolean> exchanger;

  private Boolean state;

  public InterleavedRunnable(String name, Exchanger<Boolean> exchanger, 
       Boolean state) {
    this.name = name;
    this.exchanger = exchanger;
    this.state = state;
  }         

  @Override
  public void run() {
    try {
      while (true) {
        if (state) {
          Logger.getLogger(getClass().getName()).info(name + " is running");
        }
        state = exchanger.exchange(state);
      }
    } catch (InterruptedException ex) {
      Logger.getLogger(name).info("Interrupted");
    }
  }

ランナブルの設定は非常に簡単です。

  public static void main(String[] args) {
    Exchanger<Boolean> exchanger = new Exchanger<Boolean>();
    Thread thread1 = new Thread(new InterleavedRunnable("Thread 1", exchanger, true));
    Thread thread2 = new Thread(new InterleavedRunnable("Thread 2", exchanger, false));
    thread1.start();
    thread2.start();
  }

Java API(またはよく知られているライブラリ)内に既存の機能を見つけることができるときはいつでも、それらを最大限に活用する必要があります。記述するコードの行が少ないほど、維持する行も少なくなります。

于 2013-03-11T13:14:52.780 に答える
1

「OSSycnro101」ソリューションは、スレッドごとに1つずつ、2つのセマフォを使用し、それらの間で1つの「GO」トークン/ユニットを交換することです。両方のスレッドを開始してから、最初に移動するスレッドにトークンを渡します。

于 2013-03-11T12:51:19.463 に答える
1

待機を使用して、これを通知します。

public class Thread1 implements Runnable {

@Override
public void run() {
    while(true){
        synchronized (Main.obj) {
            try {
                Main.obj.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }


        System.out.println("1");



        synchronized (Main.obj) {

            Main.obj.notify();

        }
    }

}

}


public class Thread2 implements Runnable{

@Override
public void run() {
    while(true){
        synchronized (Main.obj) {
            try {
                Main.obj.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("2");
        synchronized (Main.obj) {

            Main.obj.notify();

        }
    }

}
}


public class Main {

public volatile static Object obj =  new Object();

/**
 * @param args
 */
public static void main(String[] args) {

    Thread t1 = new Thread(new Thread1());
    Thread t2 = new Thread(new Thread2());
    t1.start();
    t2.start();
    synchronized (obj) {
        obj.notifyAll();
    }

}

}
于 2013-03-11T13:25:08.540 に答える
1

質問が正しく得られませんでした。スレッドAの実行が終了した後にのみスレッドBを実行する場合は、マルチスレッドの意味はまったくありません。スレッドBの内容をスレッドAのrun()メソッドに入れるだけです。

それでも非常に必要な場合は、2つのオブジェクトでwait()メソッドとnotify()メソッドを使用してみてください。このようなもの。

Class ClassA implements runnable{
    Message messageA;
    Message messageB;
    public ClassA(Message messageA,,Message messageB){
        this.messageA = messageA;
        this.messageB = messageB;
    }
    public void run(){
        for(;loop contition;){
            //code here
            messageB.notify();
            messageA.wait();
        }
    }
}
Class ClassB implements runnable{
    Message messageA;
    Message messageB;
    public ClassB(Message messageA,Message messageB){
        this.messageA = messageA;
        this.messageB = messageB;
    }
    public void run(){
        for(;loop condition;){
            messageB.wait();
            //code here
            messageA.notify();
        }
    }
}
  • ここで、メインのmessageAとmessageBに2つのオブジェクトを作成し、両方を各スレッドのコンストラクターに渡します。
于 2013-03-11T13:39:47.397 に答える