我遇到了Java问题。我想编写一个程序,其中有Class Main,它有一些类的ThreadList(Class Task),它只写一个字母和数字。 Object Main只是从ArrayList中唤醒一个Thread,让它在同一个对象(Main)睡眠另一个时执行某些操作。
它运作正常: 0A,0B,0C,1B,1C,1A,2B,2A,2C,3B,3C,3A,4B,4C,4A,5B,5A,5C,
但只有我评论: e.printStackTrace()e是异常 然后 我得到了很多 java.lang.IllegalMonitorStateException at java.lang.Object.notify(Native Method) 在Main.run(Main.java:22)
所以通知工作错误,我应该如何正确唤醒它,请告诉我,显示,正确。请
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();
}
}
ħ
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
}
}
答案 0 :(得分:12)
sleep
和wait
非常不同。 sleep
只是暂停当前线程达到指定的时间,并且没有与其他线程直接交互。
wait
更复杂:wait
的想法是在给定的监视器上暂停一个线程(或锁定,如果你愿意)并让其他线程工作直到它notify
在该监视器上并释放它。因此wait
和notify
涉及两个或多个线程之间的交互。
由于这种交互,为了使wait
和notify
正常工作,调用这些方法的线程必须拥有监视器(锁),这意味着object.wait()
或object.notify()
必须从synchronized(object){ ... }
块内调用。如果您在没有object.wait()
的情况下拨打synchronized
- 阻止,您将始终获得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
。
答案 1 :(得分: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();
}
}
}
}
答案 2 :(得分:1)
您需要在要等待的线程上同步():
synchronized(threads.get(i)) {
// how to put to bed the same thread ?
threads.get(i).wait();
}
答案 3 :(得分:0)
好的,我已经将其核心所以它现在是: 但我上了控制台
0A,0B,0C,0D,0E,1A,1B,1C,1D,1E,2A,2B,2C,2D,2E,I stop 10 我停止了11 我停12 我停止了13 我停止14 我停止了15
但我宁愿像0A,1A(A工作一段时间3000ms)然后另一次运行3秒等不像A,B,C,D,E,A,但更像A, A,A,B,B,B ...
但是我也无法杀死这个线程,永远没有结束循环,我想在Main死亡时杀死它。
感谢您的所有意见
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();
}
}
ħ
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();
}
}
}
}