5

Javaに問題があります。文字と数字を書くだけのクラス(クラスタスク)のスレッドのArrayListを持つクラスMainがあるプログラムを書きたいと思います。Object Mainは、ArrayListから1つのスレッドをウェイクアップし、同じオブジェクト(Main)が別のスレッドをスリープしている間に何かを実行させます。

正常に動作します:0A、0B、0C、1B、1C、1A、2B、2A、2C、3B、3C、3A、4B、4C、4A、5B、5A、5C、

ただし、コメントする場合に限ります。e.printStackTrace()eが例外の場合、Main.run(Main.java:22)のjava.lang.Object.notify(ネイティブメソッド)で多くのjava.lang.IllegalMonitorStateExceptionが発生します。

したがって、通知は正しく機能しません。どのように正しくウェイクアップする必要がありますか、教えてください、表示してください。お願いします

import java.util.ArrayList;

import java.util.ArrayList;

public class Main extends Thread {
ArrayList<Thread> threads;

public Main() {
    super();
    threads = new ArrayList<Thread>();
}

public void run() {
    for (int i = 0; i < 3; i++) {
        threads.add(new Thread(new Task(i + 65)));
    }
    long cT = System.currentTimeMillis();
    for (int i = 0; i < threads.size(); i++) {
        threads.get(i).start();
    }
    while (System.currentTimeMillis() - cT < 10000) {
        for (int i = 0; i < threads.size(); i++) {
            try {
                threads.get(i).notify();
                // HOW TO WAKE THREAD FROM threads ArrayList
                Thread.sleep(1000);
                // how to put to bed the same thread ?
                threads.get(i).wait();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

public static void main(String[] args) {
     new Main().start();
    //new Thread(new Task(65)).start();

}

}

H

public class Task implements Runnable {
int nr;
char character;

public Task(int literaASCII) {
    this.nr = 0;
    character = (char) (literaASCII);
}

@Override
public void run() {
    while (true) {
        try {
            System.out.print(nr + "" + character + ", ");
            nr++;
            int r = (int) ((Math.random() * 500) + 500); // <500ms,1000ms)
            Thread.sleep(r);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}



public static void main(String[] args) {
    // TODO Auto-generated method stub

}
}
4

4 に答える 4

14

sleepwait非常に異なります。sleep現在のスレッドを指定された時間一時停止するだけで、他のスレッドと直接対話することはありません。

waitより複雑です。特定のモニターwaitでスレッドを一時停止し(または、必要に応じてロックし)、そのモニターでスレッドが解放されるまで他のスレッドを機能させるという考え方です。したがって、2つ以上のスレッド間の相互作用が含まれます。notifywaitnotify

この相互作用のため、wait正しくnotify機能するためには、これらのメソッドを呼び出すスレッドがモニター(ロック)を所有している必要があります。つまり、object.wait()ブロック内object.notify()から呼び出される必要があります。-blockなしsynchronized(object){ ... }で呼び出すと、常に。を取得します。object.wait()synchronizedIllegalMonitorStateException

あなたのコードでは、

for (int i = 0; i < threads.size(); i++) {
  threads.get(i).start();
} 

これにより、すべてのスレッドが開始され、必要に応じて一度に1つずつではなく、すべて同時に実行されます。

一度に1つのスレッドのみが実行されるようにするには、共通のモニターオブジェクトをすべてのスレッドに渡し、それらwaitをそのモニターに配置する必要があります。例えば:

public class Main extends Thread {
  //...

  public void run(){
    //Initialize all threads with common monitor object
    Object monitor = new Object();
    for (int i = 0; i < 3; i++) {
      threads.add(new Thread(new Task(i + 65, monitor)));
    }
    long cT = System.currentTimeMillis();
    for (int i = 0; i < threads.size(); i++) {
      //All threads will start, and immediately pause on monitor.wait()
      threads.get(i).start();
    }
    synchronized(monitor){
      while (System.currentTimeMillis() - cT < 10000) {
        //All threads are currently waiting, so we need to wake one random
        //thread up by calling notify on monitor. Other thread will not run yet,
        //because this thread still holds the monitor.
        monitor.notify();

        //Make this thread wait, which will temporarily release the monitor
        //and let the notified thread run.
        monitor.wait();
      }
    }
  }
}

//...

public class Task implements Runnable{
  int nr;
  char character;
  Object monitor;

  public Task(int literaASCII, Object monitor) {
    this.nr = 0;
    this.monitor = monitor;
    character = (char) (literaASCII);
  }

  @Override
  public void run() {
    synchronized(monitor){
      while (true) {
        //Pause this thread and let some other random thread
        //do the work. When other thread finishes and calls notify()
        //this thread will continue (if this thread is picked).
        monitor.wait();

        try {
          System.out.print(nr + "" + character + ", ");
          nr++;
          int r = (int) ((Math.random() * 500) + 500); // <500ms,1000ms)

          Thread.sleep(r);
        } catch (Exception e) {
          e.printStackTrace();
        }

        //This thread has finished work for now. 
        //Let one other random thread know.
        monitor.notify();

        //Other thread will not be able to do work until this thread 
        //releases the monitor by calling monitor.wait() or 
        //completely exists the synchronized(monitor){ ... } block.
      }
    }
  }
}

スレッドはランダムにウェイクアップするため、元の意図とは少し異なる動作をする可能性があります。そのため、出力が特定の順序になる保証はありません。

また、を使用する非常に正当な理由がない限り、一般的にはを優先notifyAll()する必要があることに注意してください。1つのスレッドのみをウェイクアップするため、そのスレッドが最後に通知を呼び出すことを「忘れる」と、他のすべてのスレッドが永久に発生する可能性があります。notify()notify()notify()wait

于 2012-05-12T04:11:28.733 に答える
2

オブジェクトでwait()を呼び出すには、そのオブジェクトで同期ロックを保持する必要があります(ただし、スレッドが待機している間、ロックは実際に解放されます)。

解決策が得られた場合、次のことができます。

import java.util.ArrayList;

public class Main extends Thread {
    ArrayList<Thread> threads;

    public Main() {
        super();
        threads = new ArrayList<Thread>();

        for (int i = 0; i < 3; i++) {
            threads.add(new Thread(new Task(i + 65)));
        }

        for (int i = 0; i < threads.size(); i++) {
            threads.get(i).start();
        }

    }

    public void run() {
        long cT = System.currentTimeMillis();
        while (System.currentTimeMillis() - cT < 10000) {
            for (int i = 0; i < threads.size(); i++) {
                try {
                    synchronized (threads.get(i)) {
                        threads.get(i).notify();
                        // HOW TO WAKE THREAD FROM threads ArrayList
                        Thread.sleep(1000);
                        // how to put to bed the same thread ?
                        threads.get(i).wait();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

    }

    public static void main(String[] args) {
        new Main().start();
        // new Thread(new Task(65)).start();

    }

}

class Task implements Runnable {
    int nr;
    char character;

    public Task(int literaASCII) {
        this.nr = 0;
        character = (char) (literaASCII);
    }

    public void run() {
        while (true) {
            try {
                System.out.print(nr + "" + character + ", ");
                nr++;
                int r = (int) ((Math.random() * 500) + 500); // <500ms,1000ms)
                Thread.sleep(r);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}
于 2012-05-12T03:18:00.137 に答える
1

wait()したいスレッドで同期する必要があります:

synchronized(threads.get(i)) {
    // how to put to bed the same thread ?
    threads.get(i).wait();
}
于 2012-05-12T00:55:02.090 に答える
0

わかりました、私はそれを修正したので、今です:しかし、私はコンソールに乗ります

0A、0B、0C、0D、0E、1A、1B、1C、1D、1E、2A、2B、2C、2D、2E、停止10停止11停止12停止13停止14停止15

しかし、私はむしろ0A、1A(Aは3000msの間しばらく動作します)のようなsthが欲しいです、そして他はA、B、C、D、E、Aのようではなく、A、A、Aのように3秒間実行されます、B、B、B...。

しかし、私はこのスレッドを殺すことはできません。ループが終了することはありません。メインが死んでいる間にそれを殺したいと思います。

コメントありがとうございます

import java.util.ArrayList;

public class Main extends Thread {
ArrayList<Thread> threads;

public Main() {
    super();
    threads = new ArrayList<Thread>();
}

 public void run(){

Object monitor = new Object();
for (int i = 0; i <= 5; i++) {
  threads.add(new Thread(new Task(i + 65, monitor)));
}
long cT = System.currentTimeMillis();
for (int i = 0; i < threads.size(); i++) {
  threads.get(i).start();
}
synchronized(monitor){
  while (System.currentTimeMillis() - cT < 10000) {
      try{

    monitor.notify();
    Thread.sleep(50);


    monitor.wait();}catch(Exception e){e.printStackTrace();}
  }

for(int i = 0; i < threads.size(); i++){
    System.out.println("I suspend "+threads.get(i).getId());
    threads.get(i).stop();
}


}
 }


 public static void main(String[] args) {
     new Main().start();
    //new Thread(new Task(65)).start();

}

}

H

public class Task implements Runnable {
int nr;
char character;
Object monitor;

public Task(int literaASCII, Object monitor) {
    this.nr = 0;
    this.monitor = monitor;
    character = (char) (literaASCII);
}

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

            try {
                monitor.wait();

                System.out.print(nr + "" + character + ", ");
                nr++;
                int r = (int) ((Math.random() * 500) + 500); // <500ms,1000ms)

                Thread.sleep(r);
            } catch (Exception e) {
                e.printStackTrace();
            }

            monitor.notify();

        }
    }
}

}

于 2012-05-12T11:31:30.700 に答える