Java 具有两个线程的IllegalMonitorStateException

Java 具有两个线程的IllegalMonitorStateException,java,multithreading,Java,Multithreading,我的程序有两个线程,每个线程打印十个数字。第一个线程打印奇数,第二个线程打印偶数,它们轮流打印数字。我希望在20之前得到一个像1,2,3,4,5…这样的序列,但是程序会产生一个非法的MonitorStateException 我知道这个异常意味着什么,但我在synchronized块中使用了wait()和notify()。这是我的密码: public class EvenOddThreadTest { /** * @param args */

我的程序有两个线程,每个线程打印十个数字。第一个线程打印奇数,第二个线程打印偶数,它们轮流打印数字。我希望在20之前得到一个像1,2,3,4,5…这样的序列,但是程序会产生一个非法的MonitorStateException

我知道这个异常意味着什么,但我在synchronized块中使用了
wait()
notify()
。这是我的密码:

     public class EvenOddThreadTest {

      /**
       * @param args
       */
      static Object obj1 = new Object();
      static Object obj2 = new Object();
      static Object obj3=new EvenOddThreadTest();

      public static void main(String[] args) throws InterruptedException {
          new Thread() {
              @Override
              public void run() {

                      for (int i = 1; i < 21; i += 2) {
                          synchronized (obj1) {
                          System.out.println(i + Thread.currentThread().getName());
                          try {
                              obj2.notify();                    
                              obj1.wait();
                          } catch (InterruptedException e) {
                              e.printStackTrace();
                          }

                      }
                  }
              }
          }.start();
          new Thread() {
              @Override
              public void run() {
                      for (int i = 2; i < 21; i += 2) {
                          synchronized (obj2) {

                          System.out.println(i + Thread.currentThread().getName());
                        try {
                            obj1.notify();
                            obj2.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }

            }.start();
        }
    }

我想不出来。有什么想法吗?

您不能对您没有监视器的对象调用notify:

               synchronized (obj1) {
                  System.out.println(i + Thread.currentThread().getName());
                  try {
                      obj2.notify();  // You haven't synchronized on obj2 

在线程0中,您仅在
obj2
上同步,而不是在调用
notify
obj1
上同步。在第二个线程中,情况正好相反

这并不能直接回答您的问题,但线程级别非常低。例如,在您的情况下,您可以使用,它将为您处理同步细节:

public class Test {

    static CyclicBarrier barrier = new CyclicBarrier(2);

    public static void main(String[] args) throws InterruptedException {
        new Thread() {

            @Override
            public void run() {
                try {
                    for (int i = 1; i < 21; i += 2) {
                        System.out.println(i + Thread.currentThread().getName());
                        barrier.await();
                    }
                } catch (BrokenBarrierException e) {
                    //do something
                } catch (InterruptedException e) {
                    //do something
                }
            }
        }.start();
        new Thread() {

            @Override
            public void run() {
                try {
                    for (int i = 2; i < 21; i += 2) {
                        barrier.await();
                        System.out.println(i + Thread.currentThread().getName());
                    }
                } catch (BrokenBarrierException e) {
                    //do something
                } catch (InterruptedException e) {
                    //do something
                }
            }
        }.start();
    }
}
公共类测试{
静态循环载体屏障=新循环载体(2);
公共静态void main(字符串[]args)引发InterruptedException{
新线程(){
@凌驾
公开募捐{
试一试{
对于(int i=1;i<21;i+=2){
System.out.println(i+Thread.currentThread().getName());
障碍。等待();
}
}捕获(断线承运人例外){
//做点什么
}捕捉(中断异常e){
//做点什么
}
}
}.start();
新线程(){
@凌驾
公开募捐{
试一试{
对于(int i=2;i<21;i+=2){
障碍。等待();
System.out.println(i+Thread.currentThread().getName());
}
}捕获(断线承运人例外){
//做点什么
}捕捉(中断异常e){
//做点什么
}
}
}.start();
}
}

如果两个线程一起工作,则它们需要在同一个变量上同步。您希望一个线程等待轮到它运行,然后运行,然后通知另一个线程

public class EvenOddThreadTest {

  /**
   * @param args
   */
  static Object obj1 = new Object();
  static Object obj3=new EvenOddThreadTest();

  public static void main(String[] args) throws InterruptedException {
      new Thread() {
          @Override
          public void run() {

                  for (int i = 1; i < 21; i += 2) {
                      synchronized (obj1) {
                      try {
                          while (/* not my turn to run *?*/) {                   
                             obj1.wait();
                          }
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      System.out.println(i + Thread.currentThread().getName());
                      obj1.notify();
                  }
              }
          }
      }.start();
      new Thread() {
          @Override
          public void run() {
                  for (int i = 2; i < 21; i += 2) {
                      synchronized (obj1) {
                      try {
                          while (/* not my turn to run *?*/) {                   
                             obj1.wait();
                          }
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      System.out.println(i + Thread.currentThread().getName());
                      obj1.notify();
                }
            }
        }

        }.start();
    }
}
公共类测试{
/**
*@param args
*/
静态对象obj1=新对象();
静态对象obj3=新的EvenOddThreadTest();
公共静态void main(字符串[]args)引发InterruptedException{
新线程(){
@凌驾
公开募捐{
对于(int i=1;i<21;i+=2){
已同步(obj1){
试一试{
而(/*不轮到我跑了*?*/){
obj1.wait();
}
}捕捉(中断异常e){
e、 printStackTrace();
}
System.out.println(i+Thread.currentThread().getName());
obj1.notify();
}
}
}
}.start();
新线程(){
@凌驾
公开募捐{
对于(int i=2;i<21;i+=2){
已同步(obj1){
试一试{
而(/*不轮到我跑了*?*/){
obj1.wait();
}
}捕捉(中断异常e){
e、 printStackTrace();
}
System.out.println(i+Thread.currentThread().getName());
obj1.notify();
}
}
}
}.start();
}
}

这不会控制谁先运行,只是确保两个线程在打印第二个数字之前都打印第一个数字。
public class EvenOddThreadTest {

  /**
   * @param args
   */
  static Object obj1 = new Object();
  static Object obj3=new EvenOddThreadTest();

  public static void main(String[] args) throws InterruptedException {
      new Thread() {
          @Override
          public void run() {

                  for (int i = 1; i < 21; i += 2) {
                      synchronized (obj1) {
                      try {
                          while (/* not my turn to run *?*/) {                   
                             obj1.wait();
                          }
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      System.out.println(i + Thread.currentThread().getName());
                      obj1.notify();
                  }
              }
          }
      }.start();
      new Thread() {
          @Override
          public void run() {
                  for (int i = 2; i < 21; i += 2) {
                      synchronized (obj1) {
                      try {
                          while (/* not my turn to run *?*/) {                   
                             obj1.wait();
                          }
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      System.out.println(i + Thread.currentThread().getName());
                      obj1.notify();
                }
            }
        }

        }.start();
    }
}