5

我对 Java 有疑问。我想编写一个程序,其中有一个类 Main,它有一些类(类任务)的线程的 ArrayList,它只写一个字母和数字。Object Main 只是从 ArrayList 中唤醒一个线程,并让它在同一个对象(Main)休眠另一个线程时做某事。

它工作正常:0A、0B、0C、1B、1C、1A、2B、2A、2C、3B、3C、3A、4B、4C、4A、5B、5A、5C、

但只有当我评论:e.printStackTrace() e is Exception 然后我在 Main.run(Main.java:22) 的 java.lang.Object.notify(Native Method) 处得到很多 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

sleep并且wait非常不同。sleep只是将当前线程暂停指定的时间量,并且与其他线程没有直接交互。

wait更复杂: 的想法wait是暂停给定监视器上的线程(或锁定,如果您愿意)并让其他线程工作,直到它notify在该监视器上并释放它。因此wait,并且notify涉及两个或多个线程之间的交互。

wait由于这种交互,为了notify正常工作,调用这些方法的线程必须拥有监视器(锁),这意味着,object.wait()或者object.notify()必须从synchronized(object){ ... }块内调用。如果您在object.wait()没有synchronized-block 的情况下调用,您将始终得到一个IllegalMonitorStateException.

在您的代码中,

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

这将启动所有线程,然后同时运行它们,而不是你想要的一次。

为了确保一次只有一个线程运行一个线程,您需要将一个公共监视器对象传递给所有线程并将它们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()notify()除非你有很好的理由去使用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

您需要在要等待()的线程上进行同步:

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 工作一段时间 3000 毫秒)然后另一个运行 3 秒等。不像 A、B、C、D、E、A,但更像 A、A、A ,B,B,B....

但我也不能杀死这个线程,没有结束的循环,我想在 Main 快死的时候杀死它。

感谢您的所有评论

导入 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 回答