让runnable睡觉

时间:2012-05-12 00:46:06

标签: java multithreading notify

我遇到了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

}
}

4 个答案:

答案 0 :(得分:12)

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

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

由于这种交互,为了使waitnotify正常工作,调用这些方法的线程必须拥有监视器(锁),这意味着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();

        }
    }
}

}