2016-07-02 44 views
1

目前我正在尝试构建一个蛇游戏作为我在java中的第一个项目,并且正在使用线程。我希望有一个对象在到达屏幕边界时等待,然后在键输入进入时继续通知另一个方向。 在底部我调用notify()函数,但没有任何反应,并且线程继续处于wait()状态。任何帮助将非常感激。java无法通知()线程?

package com.foreverblu.snake; 
import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 
public class snakeobject extends JPanel{ 
int x = 0; 
int y = 0; 
int z = 0; 
int a = 0; 
Thread animationThread; 
Thread notifyThread; 
public void paintComponent(Graphics g) { 

    super.paintComponents(g); 
    this.setBackground(Color.black); 
    g.setColor(Color.GREEN); 
    g.fill3DRect(x, y, 30, 30, true); 



} 
public void keepGoing() { 
    animationThread = new Thread(create); 
    notifyThread = new Thread(create2); 
} 
Runnable create = new Runnable() { 
    public void run() { 
     synchronized(this) { 
     while(z>=0 || z<=3) { 
      if(z==2 && y>0) { 
      y-=30; 
      repaint(); 
      try{Thread.sleep(500);} catch (Exception ex) {} 
      }else if(z==1 && y<=450) { 
       y+=30; 
       repaint(); 
       try {Thread.sleep(500);} catch (Exception ex) {} 
      }else if(z==0 && x<=450) { 
       x+=30; 
       repaint(); 
       try{Thread.sleep(500);} catch (Exception ex) {} 
      }else if(z==3 && x>0) { 
       x-=30; 
       repaint(); 
       try{Thread.sleep(500);} catch (Exception ex) {} 
      }else{ 
       notifyThread.notify(); 
      } 
     } 
     } 

    } 
}; 
Runnable create2 = new Runnable() { 
    public void run() { 
     synchronized(this) { 
      try { 
       wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
      try { 
       animationThread.wait(); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     do{try{Thread.sleep(500);} catch (Exception ex) {} 
     continue; 
     }while(a==0); 
     if(a==1) { 
     System.out.println("Notified"); 

     a=0; 
     animationThread.notifyAll(); 
     } 
    } 
    } 

}; 

} 

其他职业: package com.foreverblu.snake;

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 

public class snakeframe extends JFrame{ 
int z = 0; 
snakeobject swag = new snakeobject(); 
public snakeframe() { 
    super("The Great Title"); 
    swag.keepGoing(); 
    swag.notifyThread.start(); 
    swag.animationThread.start(); 
    addKeyListener(new KeyAdapter() { 
     public void keyPressed(KeyEvent e) { 
      if(swag.animationThread.getState()==Thread.State.WAITING) { 
        swag.a=1; 
        System.out.println("Swag"); 

      } 
      if(swag.animationThread.getState()==Thread.State.RUNNABLE) { 
       System.out.println("RUNNABLE"); 
      } 
      if(e.getExtendedKeyCode()==e.VK_DOWN) { 
       swag.z=1; 

      }else if(e.getExtendedKeyCode()==e.VK_UP) { 
       swag.z=2; 
      }else if(e.getExtendedKeyCode()==e.VK_LEFT) { 
       swag.z=3; 
      }else if(e.getExtendedKeyCode()==e.VK_RIGHT) { 
       swag.z=0; 
      } 
     } 

    }); 
    add(swag); 
} 
} 
+1

嗯,你使用的等待一个/通知不正确。在一台监视器上同步,但通知另一台监视器。如果执行任何相关代码,您应该会收到异常。你不需要使用额外的线程,因为EDT和主线程就足够了。 – Kayaman

+0

你提到这是你的第一个Java项目。我建议你先去掉线程,然后再去寻求更多的基本设计。多线程不是你应该开始的事情。 – Gima

回答

0

目前,我试图建立一个蛇游戏作为我在Java中的第一个项目,并使用线程我。

你正在努力学习太多的东西在同一时间;

  • Java语言,
  • Java标准库,
  • 摇摆,以及如何设计桌面GUI应用程序,
  • 线程如何工作,以及如何使用它们来你的优势。

减速。一次带一个。


我想有一个对象的等待,当它到达屏幕的边框,然后被通知当一个键输入进来的...

这听起来不像一个线程。为游戏中的每个移动对象提供一个线程是一个非常有限的设计选择,并且有一个线程根据其状态听起来像一个糟糕的设计(IMO)而等待不同的事情。例如,当蛇正在移动时,我不会编写等待实时时钟的线程(即调用sleep()),然后在处于某种其他状态时等待按键按下。

已经有一个等待按键的线程:它被称为事件分派线程(EDT),它会在任何Swing程序中为您自动创建。而且,如果您想等待时间(例如,在游戏中为物体设置动画),那么最好使用Swing Timer


你应该知道, Swing方法(例如,repaint())可能从EDT内调用。只有极少数可以从其他线程调用SwingUtilities.invokeLater()等。


o.wait()o.notify()o.notifyAll()方法是低级别的原语是指在一个非常特定的图案来使用,以实现更高级别的同步类新。 Java标准库已经在java.util.concurrent包中定义了许多有用的同步类。任何时候你认为你想使用等待/通知,你应该首先检查java.util.concurrent中是否有一些东西能够为你节省一些努力。

如果必须使用等待/通知,那么你应该阅读Oracle的“保护模块”教程,并使用它,它是为了使用方式:https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html