So, I have a university project in java in which I'm making a bomberman game that should be run on a server. I'm having problems because of some timers that are creating new threads that are changing the object Map while I'm trying to send it.
I tried to use the synchronize(Map) on the code blocks of the timers and the outputstream but didn't work
I also have a problem where I want to keep my class Image_Library as a transient because it doesn't need to be sent over the stream, but when I mark the ArrayLists inside as such they're just considered null instead.
Here's some code:
public class GameHandler extends Thread{
private ArrayList<Client> Players = new ArrayList<Client>();
private ArrayList<Bomber> Characters = new ArrayList<Bomber>();
public GameLogic L;
transient private Image_Library lib;
private Map m;
private ArrayList<Integer> Actions = new ArrayList<Integer>();
GameHandler(Client x1, Client x2) {
x1.AddToGame(this);
x2.AddToGame(this);
Players.add(x1);
Players.add(x2);
}
#Override
public void run() {
boolean init=true;
for(int i=0;i<Players.size();i++) {
Create_New_Socket(Players.get(i));
}
Timer tt = new Timer();
tt.schedule(new Player_Info_Query(),0,200);
while(true) {
if(!init){
}
else {
int i;
for(i=0;i<Players.size();i++)
if(Players.get(i).GetBomber()==null)
break;
if(i==Players.size()) {
init=false;
tt.cancel();
try {
init_game();
for(i=0;i<Players.size();i++) {
Players.get(i).dos.writeUTF("game_start");
}
Timer tt2 = new Timer();
tt2.schedule(new Update_Task(),100);
} catch (SlickException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
private class Player_Info_Query extends TimerTask{
#Override
public void run() {
for(int i=0;i<Players.size();i++) {
if(Players.get(i).GetBomber()!=null)
continue;
try {
Players.get(i).Request_Client_Player();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
private class Update_Task extends TimerTask{
#Override
public void run() {
// TODO Auto-generated method stub
try {
while(Actions.size()!=0) {
L.Action(Actions.get(0));
Actions.remove(0);
}
lib.Run_Changes();
} catch (SlickException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
for(int i=0;i<Players.size();i++)
try {
Players.get(i).Send_Map(m);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Timer tt2 = new Timer();
tt2.schedule(new Update_Task(),100);
}
}
private void Create_New_Socket(Client x){
try {
x.objectsocket = new Socket(x.datasocket.getInetAddress(),x.outputsocket);
System.out.println("SOCKET CREATED " + x.objectsocket);
x.oos = new ObjectOutputStream(x.objectsocket.getOutputStream());
x.ois = new ObjectInputStream(x.objectsocket.getInputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// obtaining input and out streams
}
private void init_game() throws SlickException {
lib = new Image_Library();
Layout_Logic map_gen = new Layout_Logic(lib);
m = map_gen.Generate_Standard_Map();
L=new GameLogic(lib,m);
Characters = new ArrayList<Bomber>();
for(int i=0;i<Players.size();i++){
Characters.add(Players.get(i).GetBomber());
}
L.Place_Characters(Characters);
}
public void Buffer_Input(int key){
Actions.add(key);
}
}
package GameLogic;
import java.io.Serializable;
import java.util.ArrayList;
import org.newdawn.slick.SlickException;
public class Image_Library implements Serializable{
/**
*
*/
private static final long serialVersionUID = -8459759623730666317L;
private ArrayList<Element> Flagged = new ArrayList<Element>();
private ArrayList<String> Flagged_images = new ArrayList<String>();
public Map m;
public void Flag_For_Change(Element x,String img){
Flagged.add(x);
Flagged_images.add(img);
}
public void Run_Changes() throws SlickException {
while(Flagged.size()!=0 && Flagged_images.size()!=0) {
Flagged.get(0).Set_Image(Flagged_images.get(0));
Flagged.remove(0);
Flagged_images.remove(0);
}
}
}
package GameLogic;
import org.newdawn.slick.SlickException;
import java.util.Timer;
import java.util.TimerTask;
public class Bomber extends Element{
/**
*
*/
private static final long serialVersionUID = -9085303141098935687L;
transient protected boolean bomb_cd;
transient protected boolean Walking_cd;
static private int cooldown = 500; //milliseconds
static private int bomb_cooldown=1000;
static protected int move_res = 5;
protected int progression_count=move_res;
protected int direction; //0-down 1-left 2-up 3-right
static protected String StopDown="StopDown";
static protected String Down1="Down1";
static protected String Down2="Down2";
static protected String StopUp="StopUp";
static protected String Up1="Up1";
static protected String Up2="Up2";
static protected String StopLeft="StopLeft";
static protected String Left1="Left1";
static protected String Left2="Left2";
static protected String StopRight="StopRight";
static protected String Right1="Right1";
static protected String Right2="Right2";
protected int upkey,downkey,rightkey,leftkey,actionkey;
private int player;
public Bomber(int x,int y,Image_Library lib,Map m,int c1,int c2,int k1,int k2, int k3, int k4,int k5,int p) throws SlickException{
Coordinate tmp = new Coordinate(x,y);
Coord=tmp;
Solid=true;
this.lib=lib;
this.m=m;
img=StopDown;
upkey=k1;
downkey=k2;
leftkey=k3;
rightkey=k4;
actionkey=k5;
player=p;
img = StopDown;
bomb_cd=false;
Walking_cd=false;
//direction=0;
GUI_Scale=64;
}
public void MoveUp() {
Coord.MoveUp();
direction=2;
Start_Walking();
}
public void MoveRight() {
Coord.MoveRight();
direction=3;
Start_Walking();
}
public void MoveLeft() {
Coord.MoveLeft();
direction=1;
Start_Walking();
}
public void MoveDown() {
Coord.MoveDown();
direction=0;
Start_Walking();
}
private void Start_Walking(){
Walking_cd=true;
Timer tt = new Timer();
tt.schedule(new Walking(this),0,cooldown/move_res);
progression_count=0;
}
public void Used_Bomb(){
bomb_cd=true;
Timer tt = new Timer();
tt.schedule(new Bomb_Cd(), bomb_cooldown);
}
public boolean Can_Use_Bomb(){
return !bomb_cd;
}
public boolean Can_Walk() {
return !Walking_cd;
}
public boolean Death_Check(){
return m.Has_Explosion(Coord.getX(),Coord.getY());
}
private class Bomb_Cd extends TimerTask{
public void run(){
synchronized(m) {
bomb_cd=false;
}
}
}
private class Walking extends TimerTask{
transient private boolean feet=false;
private Bomber person;
Walking (Bomber person){
this.person=person;
bomb_cd=true;
}
public void run(){
progression_count++;
if(feet) {
if(direction==0)
lib.Flag_For_Change(person,Down1);
if(direction==1)
lib.Flag_For_Change(person,Left1);
if(direction==2)
lib.Flag_For_Change(person,Up1);
if(direction==3)
lib.Flag_For_Change(person,Right1);
}
else {
if(direction==0)
lib.Flag_For_Change(person,Down2);
if(direction==1)
lib.Flag_For_Change(person,Left2);
if(direction==2)
lib.Flag_For_Change(person,Up2);
if(direction==3)
lib.Flag_For_Change(person,Right2);
}
feet=!feet;
if(progression_count==move_res){
Walking_cd=false;
if(direction==0)
lib.Flag_For_Change(person,StopDown);
if(direction==1)
lib.Flag_For_Change(person,StopLeft);
if(direction==2)
lib.Flag_For_Change(person,StopUp);
if(direction==3)
lib.Flag_For_Change(person,StopRight);
bomb_cd=false;
this.cancel();
}
}
}
}
Related
I have this custom video capturer class:
...
import org.webrtc.JavaI420Buffer;
import org.webrtc.SurfaceTextureHelper;
import org.webrtc.VideoCapturer;
import org.webrtc.VideoFrame;
import java.nio.ByteBuffer;
public class CustomCapturer implements VideoCapturer {
private SurfaceTextureHelper surTexture;
private Context appContext;
private org.webrtc.CapturerObserver capturerObs;
private Thread captureThread;
#Override
public void initialize(SurfaceTextureHelper surfaceTextureHelper, Context applicationContext, org.webrtc.CapturerObserver capturerObserver) {
surTexture = surfaceTextureHelper;
appContext = applicationContext;
capturerObs = capturerObserver;
}
public void addFrame(Bitmap frame_asbitmap) {
try {
final long captureTimeNs =
TimeUnit.MILLISECONDS.toNanos(SystemClock.elapsedRealtime());
long start = System.nanoTime();
JavaI420Buffer buffer = JavaI420Buffer.allocate(640, 480);
bitmapToI420(frame_asbitmap, buffer);
long frameTime = System.nanoTime() - start;
VideoFrame videoFrame = new VideoFrame(buffer, 0, frameTime);
capturerObs.onFrameCaptured(videoFrame);
} catch (Exception e) {
}
}
#Override
public void startCapture(int width, int height, int fps) {
captureThread = new Thread(() -> {
try {
long start = System.nanoTime();
capturerObs.onCapturerStarted(true);
} catch(InterruptedException ex) {
ex.printStackTrace();
}
});
captureThread.start();
}
#Override
public void stopCapture() {
captureThread.interrupt();
}
#Override
public void changeCaptureFormat(int width, int height, int fps) {
}
#Override
public void dispose() { }
#Override
public boolean isScreencast() {
return false;
}
}
How to use this as a source for the local video track? I have looked for documentation on this but could not find any. I plan to attach this class to the local video track and then add frames to it form a USB camera using the addFrame(Bitmap frame_asbitmap) method from MainActivity.
I am currently developing a MOBA like game with libGDX, but I am struggling with the Server. Currently I have got a thread for every connection and a critical region wich stores the data. My problem is, that there are Threads, which are writing into the critical region and reading from it simultaneously. Can somebody help me out?
Here are my classes:
Clientthread:
package at.mobaserver;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import at.motm.model.GameObject;
import at.motm.model.Projectile;
import com.badlogic.gdx.math.Intersector;
import com.badlogic.gdx.math.Rectangle;
public class ClientConnection implements Runnable
{
private ObjectInputStream ois;
private ObjectOutputStream oos;
private Socket socket;
private GameServer server;
private GameObject receivedObject;
private Rectangle r;
private Projectile projectile;
private boolean found;
public ClientConnection(Socket socket, GameServer server)
{
try
{
this.socket = socket;
this.oos = new ObjectOutputStream(socket.getOutputStream());
this.ois = new ObjectInputStream(socket.getInputStream());
this.server = server;
this.receivedObject = null;
this.projectile = null;
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void run()
{
try
{
this.oos.writeLong(Thread.currentThread().getId());
this.oos.flush();
}
catch (IOException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
while (true)
{
try
{
// Add GameObjects to list
// this.server.getMutex().lock();
this.oos.reset();
// Hitdetection
if (this.projectile != null)
{
projectileHitDetection();
}
// Write Objects to client
this.oos.writeObject(this.server.getSendingList());
this.oos.flush();
// Add Objects to Severobject Arraylist
// this.server.getMutex().lock();
addObjectsToList();
// Add Projectiles to Serverobject Arraylist
readProjectiles();
// this.server.getMutex().unlock();
// this.server.getMutex().unlock();
}
catch (ClassNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
break;
}
}
}
private void readProjectiles() throws ClassNotFoundException, IOException
{
synchronized (this.server.getProjectiles())
{
this.projectile = (Projectile) this.ois.readObject();
if (this.projectile != null)
{
this.found = false;
for (int i = 0; i < this.server.getProjectiles().size(); i++)
{
if (this.server.getProjectiles().get(i).getThreadID() == Thread
.currentThread().getId())
{
this.server.getProjectiles().set(i, this.projectile);
this.found = true;
break;
}
}
if (!this.found)
{
this.server.getProjectiles().add(this.projectile);
}
}
}
}
private void addObjectsToList() throws ClassNotFoundException, IOException
{
synchronized (this.server.getObjects())
{
this.receivedObject = (GameObject) this.ois.readObject();
this.found = false;
for (int i = 0; i < this.server.getObjects().size(); i++)
{
if (this.server.getObjects().get(i).getThreadID() == Thread
.currentThread().getId())
{
this.server.getObjects().set(i, this.receivedObject);
this.found = true;
break;
}
}
if (!this.found)
{
this.server.addObject(this.receivedObject);
}
}
}
private void projectileHitDetection()
{
synchronized (this.server.getObjects())
{
this.r = new Rectangle(this.projectile.getPosition().x,
this.projectile.getPosition().y,
this.projectile.getWidth(), this.projectile.getHeight());
for (int i = 0; i < this.server.getObjects().size(); i++)
{
if (this.server.getObjects().get(0).getTeam() != this.projectile
.getTeam())
{
Rectangle r1 = new Rectangle(this.server.getObjects()
.get(0).getPosition().x, this.server.getObjects()
.get(0).getPosition().y, this.server.getObjects()
.get(0).getWidth(), this.server.getObjects().get(0)
.getHeight());
if (Intersector.overlaps(this.r, r1))
{
System.out.println("test");
this.server.getProjectiles().remove(this.projectile);
break;
}
}
}
}
}
}
Critical region:
package at.mobaserver;
import java.util.ArrayList;
import at.motm.model.GameObject;
import at.motm.model.Projectile;
public class GameServer
{
private ArrayList<GameObject> objects;
private ArrayList<Projectile> projectiles;
private ArrayList<GameObject> sendList;
public GameServer()
{
this.objects = new ArrayList<GameObject>();
this.projectiles = new ArrayList<Projectile>();
this.sendList = new ArrayList<GameObject>();
}
public ArrayList<GameObject> getSendingList()
{
synchronized (this.sendList)
{
this.sendList.clear();
for (GameObject o : this.objects)
{
if (o.isAlive())
{
this.sendList.add(o);
}
}
this.sendList.addAll(this.projectiles);
return this.sendList;
}
}
public ArrayList<GameObject> getObjects()
{
synchronized (this.objects)
{
return this.objects;
}
}
public void setObjects(ArrayList<GameObject> objects)
{
synchronized (objects)
{
this.objects = objects;
}
}
public void addObject(GameObject o)
{
synchronized (this.sendList)
{
this.objects.add(o);
}
}
public ArrayList<Projectile> getProjectiles()
{
synchronized (this.projectiles)
{
return this.projectiles;
}
}
public void setProjectiles(ArrayList<Projectile> projectiles)
{
synchronized (this.projectiles)
{
this.projectiles = projectiles;
}
}
public void addProjectile(Projectile o)
{
synchronized (this.sendList)
{
this.projectiles.add(o);
}
}
}
I have solved my problem. I used CopyAndWriteArrayList instead of normal ArrayLists.
I am trying to write a basic Java Swing application that works as such: an Arduino writes two CSV strings to the COM port every second, I read that data and parse it, and then display the data in a GUI. With some help from the official Arduino tutorials, I am at the point where I can read and parse the data coming in from the serial port, and display it. However, I would be able to pause and resume the GUI (while still reading from serial) using a key on the keyboard. I was able to pause the program, but cannot figure out how to resume it. I've been looking around online for a while now to no avail. If someone could point me in the right direction, I'd sincerely appreciate it. I'm rather new to threads and the Arduino, but have some basic Java experience. Here is the code below, which is broken up into three classes (one to read from serial, one for the GUI, and a main class to run everything. Thanks!
Here is the "Display" class:
//Imports
import java.awt.*;
import javax.swing.*;
import java.util.Random;
import java.lang.Thread;
import java.awt.event.*;
import java.util.ArrayList;
import java.awt.Toolkit.*;
//Class Definition
public class Display extends JPanel implements Runnable {
//Variables
private volatile Thread t;
private volatile boolean threadSuspended;
//Data Strings
private String data;
private String carData;
private String gpsData;
//Car Data
private int event;
private int engineRPM;
private int cvtRPM;
private double kph;
private int brake;
private double accel_x;
private double accel_y;
private double accel_z;
private double gyro_x;
private double gyro_y;
private double gyro_z;
//GPS Data
private String sentence;
private int time;
private String status;
private double latitude;
private String latitudeDir;
private double longitude;
private String longitudeDir;
private double knots;
private double angle;
private int date;
private double magVar;
private char magVarDir;
private String checksum;
//Constructor
public Display() {
super.setSize(800,800);
setLayout(new BorderLayout());
addKeyListener(new KeyHandler());
setFocusable(true);
start();
}
public void start() {
t = new Thread(this);
t.start();
threadSuspended = false;
}
public synchronized void stop() {
t = null;
notify();
threadSuspended = true;
}
#Override
public void run() {
Thread thisThread = Thread.currentThread();
while(t == thisThread) {
try {
Thread.sleep(1000);
synchronized(this) {
while (threadSuspended && t == thisThread) {
wait();
}
}
} catch (InterruptedException ie) {
ie.printStackTrace();
}
repaint();
save();
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
kph = SerialReader.getKPH();
System.out.println(kph);
g.drawString("Speed of Car: " + kph, 35, 35);
}
//Writes values to a file and updates average values
public void save() {
//Nothing here yet
}
private class KeyHandler extends KeyAdapter {
#Override
public synchronized void keyPressed(KeyEvent ke) {
ke.consume();
int key = ke.getKeyCode();
if (key == KeyEvent.VK_SPACE) {
threadSuspended = !threadSuspended;
if (!threadSuspended) {
notify();
}
}
}
}
}
Here is the "SerialReader" class:
//Imports
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import java.util.Enumeration;
//Class definition
public class SerialReader implements SerialPortEventListener {
//Data Strings
private static String data;
private static String carData;
private static String gpsData;
//Car Data
private static int event;
private static int engineRPM;
private static int cvtRPM;
private static double kph;
private static int brake;
private static double accel_x;
private static double accel_y;
private static double accel_z;
private static double gyro_x;
private static double gyro_y;
private static double gyro_z;
//GPS Data
private static String sentence;
private static int time;
private static String status;
private static double latitude;
private static String latitudeDir;
private static double longitude;
private static String longitudeDir;
private static double knots;
private static double angle;
private static int date;
private static double magVar;
private static char magVarDir;
private static String checksum;
//Variables
SerialPort serialPort;
private static final String[] PORT_NAMES = {"/dev/tty.usbserial-A9007UX1", "/dev/ttyUSB0", "COM3"};
private BufferedReader input;
private OutputStream output;
private static final int TIME_OUT = 2000;
private static final int DATA_RATE = 9600;
//Constructor
public SerialReader() {}
//Opens port
public void initialize() {
CommPortIdentifier portId = null;
Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();
while (portEnum.hasMoreElements()) {
CommPortIdentifier currPortId = (CommPortIdentifier) portEnum.nextElement();
for (String portName : PORT_NAMES) {
if (currPortId.getName().equals(portName)) {
portId = currPortId;
break;
}
}
}
if (portId == null) {
System.out.println("Could not find COM port.");
return;
}
try {
// open serial port, and use class name for the appName.
serialPort = (SerialPort) portId.open(this.getClass().getName(),
TIME_OUT);
// set port parameters
serialPort.setSerialPortParams(DATA_RATE,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
// open the streams
input = new BufferedReader(new InputStreamReader(serialPort.getInputStream()));
output = serialPort.getOutputStream();
// add event listeners
serialPort.addEventListener(this);
serialPort.notifyOnDataAvailable(true);
} catch (Exception e) {
//Do nothing
}
}
//Called when port is no longer in use
public synchronized void close() {
if (serialPort != null) {
serialPort.removeEventListener();
serialPort.close();
System.out.println("Port Closed");
}
}
//Reads data from serial port
public synchronized void serialEvent(SerialPortEvent spe) {
if (spe.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
try {
data = input.readLine();
//System.out.println(data);
if (data.charAt(0) == '$') {
gpsData = data;
parseGPSData(data);
} else {
carData = data;
parseCarData(data);
}
} catch (Exception e) {
//Do nothing
}
}
}
//Parse car data
public void parseCarData(String data) {
String[] info = data.split(",");
event = Integer.parseInt(info[0]);
engineRPM = Integer.parseInt(info[1]);
cvtRPM = Integer.parseInt(info[2]);
kph = Double.parseDouble(info[3]);
brake = Integer.parseInt(info[4]);
accel_x = Double.parseDouble(info[5]);
accel_y = Double.parseDouble(info[6]);
accel_z = Double.parseDouble(info[7]);
gyro_x = Double.parseDouble(info[8]);
gyro_y = Double.parseDouble(info[9]);
gyro_z = Double.parseDouble(info[10]);
}
//Parse GPS data
public void parseGPSData(String data) {
String[] info = data.split(",");
sentence = info[0];
int time = Integer.parseInt(info[1]);
status = info[2];
latitude = Double.parseDouble(info[3]);
latitudeDir = info[4];
longitude = Double.parseDouble(info[5]);
longitudeDir = info[6];
knots = Double.parseDouble(info[7]);
angle = Double.parseDouble(info[8]);
date = Integer.parseInt(info[9]);
magVar = Double.parseDouble(info[10]);
magVarDir = info[11].charAt(0);
checksum = info[11].substring(1);
}
//Accessor Methods
public static String getCarData() {
return carData;
}
public static String getGPSData() {
return gpsData;
}
public static int getEvent() {
return event;
}
public static int getEngineRPM() {
return engineRPM;
}
public static int getCvtRPM() {
return cvtRPM;
}
public static double getKPH() {
return kph;
}
public static int getBrake() {
return brake;
}
public static double getAccel_X() {
return accel_x;
}
public static double getAccel_Y() {
return accel_y;
}
public static double getAccel_Z() {
return accel_z;
}
public static double getGyro_X() {
return gyro_x;
}
public static double getGyro_Y() {
return gyro_y;
}
public static double getGyro_Z() {
return gyro_z;
}
public static String getSentence() {
return sentence;
}
public static int getTime() {
return time;
}
public static String getStatus() {
return status;
}
public static double getLatitude() {
return latitude;
}
public static String getLatitudeDir() {
return latitudeDir;
}
public static double getLongitude() {
return longitude;
}
public static String getLongitudeDir() {
return longitudeDir;
}
public static double getKnots() {
return knots;
}
public static double getAngle() {
return angle;
}
public static int getDate() {
return date;
}
public static double getMagVar() {
return magVar;
}
public static char getMagVarDir() {
return magVarDir;
}
public static String getChecksum() {
return checksum;
}
}
And lastly, the "Main" class:
//Imports
import java.awt.*;
import javax.swing.*;
//Class Definition
public class Main {
//Variables
private static JFrame frame;
private static Display display;
private static Container pane;
private static Dimension dim;
private static SerialReader sr;
private static Thread t;
//Run the program
public static void main(String[] args) {
sr = new SerialReader();
sr.initialize();
t = new Thread() {
public void run() {
try {
Thread.sleep(1000000);
} catch (InterruptedException ie) {
//Do nothing
}
}
};
t.start();
System.out.println("Started");
//Set look and feel to that of OS
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
frame = new JFrame("Baja GUI, Version 0.1");
frame.setSize(800,800);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
display = new Display();
pane = frame.getContentPane();
pane.add(display);
//Place frame in the middle of the screen
dim = Toolkit.getDefaultToolkit().getScreenSize();
frame.setLocation(dim.width/2-frame.getSize().width/2, dim.height/2-frame.getSize().height/2);
frame.setVisible(true);
}
}
When I compile and run the StartThreads Class I get a list of integer 1 to 1000000 with false and at the end it prints true;
Now what I'm trying to find out is why does class threadone print nothing when it should print once the instance variable in class MyVariables = true?
public class MyVariables {
public boolean startApp = false;
}
public class ThreadOne implements Runnable {
Thread t;
MyVariables x;
public ThreadOne(MyVariables x) {
t = new Thread(this, "Thread One");
this.x = x;
}
#Override
public void run() {
while(this.x.startApp != false) {
System.out.println("Starting");
}
}
public void start() {
t.start();
}
}
public class ThreadTwo implements Runnable {
Thread t;
MyVariables x;
public ThreadTwo(MyVariables x) {
t = new Thread(this, "Thread One");
this.x = x;
}
#Override
public void run() {
synchronized(this.x) {
for(int i = 0; i <= 1000001; i++) {
if(i == 1000001) {
this.x.startApp = true;
System.out.println(this.x.startApp);
}
else {
System.out.println(this.x.startApp);
System.out.println(i);
}
}
}
}
public void start() {
t.start();
}
}
public class StartThreads {
public static void main(String[] args) {
MyVariables a = new MyVariables();
ThreadOne x = new ThreadOne(a);
ThreadTwo y = new ThreadTwo(a);
x.start();
y.start();
}
}
Why should ThreadOne behave as you're stating? It's while loop is never run but rather is skipped over since the condition is not true. I think that you're expecting it to wait for something to change to true, but it does nothing of the sort, and instead once it sees that a condition is false, finishes execution.
Note that this is ugly code:
while(this.x.startApp != false) {
Why state while something is not false? That's the same as being true.
Better
while (x.startApp) {
Now as for your actual problem, perhaps you should instead make your while loop:
while (!x.startApp) {
Thread.sleep(1); // surrounded with try/catch
}
System.out.println("Starting");
e.g.,
class ThreadOne implements Runnable {
Thread t;
volatile MyVariables x;
public ThreadOne(MyVariables x) {
t = new Thread(this, "Thread One");
this.x = x;
}
#Override
public void run() {
while (!x.startApp) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
}
}
System.out.println("Starting");
}
public void start() {
t.start();
}
}
class ThreadTwo implements Runnable {
private static final int MAX_I = 10001;
Thread t;
volatile MyVariables x;
public ThreadTwo(MyVariables x) {
t = new Thread(this, "Thread One");
this.x = x;
}
#Override
public void run() {
synchronized (this.x) {
for (int i = 0; i <= MAX_I; i++) {
if (i == MAX_I) {
this.x.startApp = true;
System.out.println(this.x.startApp);
} else {
System.out.println(this.x.startApp);
System.out.println(i);
}
}
}
}
public void start() {
t.start();
}
}
public class StartThreads {
public static void main(String[] args) {
MyVariables a = new MyVariables();
ThreadOne x = new ThreadOne(a);
ThreadTwo y = new ThreadTwo(a);
x.start();
y.start();
}
}
class MyVariables {
public volatile boolean startApp = false;
}
Also, I think that your boolean field should at the least be volatile.
Another way using a PropertyChangeListener and the observer pattern:
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
public class StartThreads2 {
public static void main(String[] args) {
final MyVariables2 myVars2 = new MyVariables2();
final RunOne runOne = new RunOne();
final RunTwo runTwo = new RunTwo(myVars2);
myVars2.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if (MyVariables2.START_APP.equals(pcEvt.getPropertyName())) {
if (pcEvt.getNewValue().equals(Boolean.TRUE)) {
new Thread(runOne).start();
}
}
}
});
new Thread(runTwo).start();
}
}
class MyVariables2 {
public static final String START_APP = "start app";
private volatile boolean startApp = false;
private PropertyChangeSupport pcSupport = new PropertyChangeSupport(this);
public boolean isStartApp() {
return startApp;
}
public void setStartApp(boolean startApp) {
boolean oldValue = this.startApp;
boolean newValue = startApp;
this.startApp = startApp;
pcSupport.firePropertyChange(START_APP, oldValue, newValue);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
}
class RunOne implements Runnable {
#Override
public void run() {
System.out.println("Starting RunOne");
}
}
class RunTwo implements Runnable {
private static final int MAX_I = 10001;
private MyVariables2 myVars2;
public RunTwo(MyVariables2 myVars2) {
this.myVars2 = myVars2;
}
#Override
public void run() {
for (int i = 0; i <= MAX_I; i++) {
System.out.println("startApp: " + myVars2.isStartApp());
System.out.printf("i: %05d%n", i);
}
myVars2.setStartApp(true);
try {
Thread.sleep(10);
} catch (InterruptedException e) {}
System.out.println("startApp: " + myVars2.isStartApp());
}
}
I have a simple list field class which shows the default menu when I select a particular listitem. I want to customize the listfield item, so that when an item is selected a new screen is pushed onto the stack. I am overridding trackwheeel() method, but am not able to make it work.
import net.rim.device.api.system.*;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import java.util.Vector;
public class TeamListScreen extends UiApplication
{
public static void main(String[] args)
{
TeamListScreen theApp = new TeamListScreen();
theApp.enterEventDispatcher();
}
public TeamListScreen()
{
pushScreen(new ListFieldScreen());
}
}
class ListFieldScreen extends MainScreen
{
private ListField _listField;
private Vector _listElements;
int listFieldIndex = -1;
public ListFieldScreen()
{
setTitle("List Field Sample");
_listElements = new Vector();
_listField = new ListField();
ListCallback _callback = new ListCallback();
_listField.setCallback(_callback);
_listField.setRowHeight(45);
//_listField.setChangeListener(this);
add(_listField);
initializeList();
_listField = new ListField(_listElements.size()) {
protected void drawFocus(Graphics graphics, boolean on) {
}
protected boolean trackwheelClick(int status, int time) {
listFieldIndex = _listField.getSelectedIndex();
if (listFieldIndex < 0) {
listFieldIndex = 0;
}
try {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
UiApplication.getUiApplication().pushScreen(new LiveScreen());
// UiApplication.getUiApplication().popScreen(getActiveScreen());
}
});
} catch (Exception e) {
}
return true;
}
};
}
private void initializeList()
{
String itemOne = "List item one";
String itemTwo = "List item two";
_listElements.addElement(itemOne);
_listElements.addElement(itemTwo);
reloadList();
}
private void reloadList()
{
_listField.setSize(_listElements.size());
}
private class ListCallback implements ListFieldCallback
{
public void drawListRow(ListField list, Graphics g, int index, int y, int w)
{
String text = (String)_listElements.elementAt(index);
g.drawText(text, 0, y, 0, w);
}
public Object get(ListField list, int index)
{
return _listElements.elementAt(index);
}
public int indexOfList(ListField list, String prefix, int string)
{
return _listElements.indexOf(prefix, string);
}
public int getPreferredWidth(ListField list)
{
return Display.getWidth();
}
}
}
trackwheelClick() function is deprecated, you should use navigationClick() instead.
BTW, you don't need to use UiApplication.getUiApplication().invokeLater, because it is already running in the event queue.