Client/Server communication - Guess my animal game - java

I have to make a simple text based game using multi threading. I have chosen to do a guess my animal game. A server will pick a random animal and give out clues and the client has to guess what the animal is within three clues.
However, if the animal is guessed correct, the program just goes to the next clue. I dont understand where i have gone wrong?
The other problem is when the client says y to a new game, it just repeats the same animal. It won't change.
I know it is just the protocol class i need to fix. Please help! I have cried with frustration over this program.
Here is a copy of my protocol class:
public class KKProtocol {
private static final int WAITING = 0;
private static final int ASKNAME = 1;
private static final int SENTCLUE = 2;
private static final int SENTCLUE2 = 3;
private static final int SENTCLUE3 = 4;
private static final int ANOTHER = 5;
private static final int NUMANIMALS = 4;
private int state = WAITING;
private int currentAnimal = (int) (Math.random() * 6); // number of first joke
private String[] clues = {"I like to play", "I like to scratch", "I eat salad", "I annoy you in the morning"};
private String[] clues2 = {"Love walks", "House pet", "garden pet", "I fly everywhere"};
private String[] clues3 = {"Woof", "Meow", "I live in a hutch", "Tweet Tweet"};
private String[] answers = {"Dog",
"Cat",
"Rabbit",
"Bird",};
private String[] name = {};
public String processInput(String theInput) {
String theOutput = null;
// System.out.println("Welcome to my animal guessing game");
if (state == WAITING) {
theOutput = clues[currentAnimal];
state = SENTCLUE;
} else if (state == SENTCLUE) {
if (theInput.equals(answers[currentAnimal])) {
theOutput = "Correct...Your Score is 1....Want to play again? (y/n)";
state = ANOTHER;
} else {
theOutput = clues2[currentAnimal];
state = SENTCLUE2;
}
} else if (state == SENTCLUE2) {
if (theInput.equals(answers[currentAnimal])) {
theOutput = "Correct...Your Score is 2....Want to play again? (y/n)";
state = ANOTHER;
} else {
theOutput = clues3[currentAnimal];
state = SENTCLUE3;
}
} else if (state == SENTCLUE3) {
if (theInput.equals(answers[currentAnimal])) {
theOutput = "Correct...Your Score is 3....Want to play again? (y/n)";
state = ANOTHER;
} else {
theOutput = ("it's" + answers[currentAnimal] + " you fool! Want to play again? (y/n)");
state = ANOTHER;
}
} else if (state == ANOTHER) {
if (theInput.equalsIgnoreCase("y")) {
if (currentAnimal == (NUMANIMALS - 1)) {
currentAnimal = 0;
}
theOutput = clues[currentAnimal];
// else
currentAnimal++;
state = SENTCLUE;
} else {
theOutput = "Bye.";
state = WAITING;
}
}
return theOutput;
}
}
If you need to see the other classes please just ask.

Debug the program and set a break point before your first if clause. How do the variables look like? I suppose you've made a trivial error somewhere in your code which will reveal itself while observing what your program actually does.
You could also paste some of your client code here so that someone could understand what is happening. From the comments I understood that nobody quite got how you use the Protocol class.

Related

Problem with Class scope, how should I resolve this?

I started my first java project and I get stuck in class scope. I cant initiate below code:
if (guessAttemts = MaxGuesses) {
System.out.println("Sorry you used all your nine chances. Game Over.)
I will be appreciate if someone will help me to clarify what I doing wrong with that code: This NewGame class look like below.
class NewGame {
GuessAttempts GuessAttempts = new GuessAttempts();
private String WordToGuess;
private String CorrectGuesses;
private String misses;
int guessAttempts;
int MAX_Guesses = 9;
public NewGame(String WordToGuess) {
this.WordToGuess = WordToGuess;
CorrectGuesses = "";
misses = "";
guessAttempts = 0;
}
public boolean UserGuessing(char letter) {
boolean isHit = WordToGuess.indexOf(letter) != -1;
if (isHit) {
CorrectGuesses += letter;
} else {
misses += letter;
}
guessAttempts =+ 1;
return isHit;
}
if (guessAttemts = MaxGuesses) {
System.out.println("Sorry you used all your nine chances. Game Over.");
}
}
To compare to values, you should use ==.
That means that your if-statement should look so:
if (guessAttemts == MaxGuesses) {
System.out.println("Sorry you used all your nine chances. Game Over.");
}

Cannot quit this loop?

I wrote a simple guessing game which uses while loop.
If user types any word with an initial of "y", the game will run again, but if user types any other word, the game will quit and gives out the report.
public static void loopcalc(Scanner console) {
int totalRounds = 0, totalGuesses = 0, best = 1000000;
boolean want = true;
while (want = true) {
int eachguess = playOneGame(console);
totalRounds++;
totalGuesses += eachguess;
System.out.println("Do you want to play again?");
String input = console.next();
if (input.toLowerCase().charAt(0) == 'y') {
want = true;
} else {
want = false;
}
best = Math.min(eachguess, best);
}
report(console, totalGuesses, totalRounds, best);
}
Sorry I do not know how to type codes correctly.
You wrote:
while(want = true) {
You surely want to check if want is true. So write instead:
while(want == true) {
Or, better:
while(want) {
In Java, = is an operator which assigns a value to a variable. It returns also the value. So, when you type wanted = true, you:
Set want to true
Return true
Here, while returns gets true, and continue the loop infinitely.
Ps : this is a very frequent issue. In 2003, a famous attempt to insert a backdoor in the Linux kernel used this feature (C language has it too).
This is your updated answer.
public static void loopcalc(Scanner console) {
int totalRounds = 0, totalGuesses = 0, best = 1000000;
boolean want = true;
while (want) {
int eachguess = playOneGame(console);
totalRounds++;
totalGuesses += eachguess;
System.out.println("Do you want to play again?");
String input = console.next();
if (input.toLowerCase().charAt(0) == 'y') {
want = true;
} else {
want = false;
}
best = Math.min(eachguess, best);
}
report(console, totalGuesses, totalRounds, best);
}
You can also try following approach and get rid of want variable:
public static void loopcalc(Scanner console) {
int totalRounds = 0, totalGuesses = 0, best = 1000000;
boolean want = true;
while (true) {
int eachguess = playOneGame(console);
totalRounds++;
totalGuesses += eachguess;
System.out.println("Do you want to play again?");
String input = console.next();
if (input.toLowerCase().charAt(0) == 'n') {
break;
}
best = Math.min(eachguess, best);
}
report(console, totalGuesses, totalRounds, best);
}
= in want = true is an assignment operator. What you should try instead is the equality == operator.
while(want == true) or while(want)

Unfair Candy Distribution

I am completing an assignment and am having a hard time figuring out the logic need to make the program work. I do not want a direct answer but could someone point me in the right direction?
Assignment:
Define a class named UnfairCandyDistributor. An UnfairCandyDistributor object represents a mean big brother who is going to divide a set of candies between himself and his hungry little brother. This will be done unfairly: for every candy given to the sibling, the big brother takes for himself a number of additional candies equal to the younger sibling's total. Each UnfairCandyDistributor object should have the same method:
public void nextCandy()
Each time nextCandy is called, the method prints a message about who gets a candy. Each call to nextCandy produces a single line of output. This time the output is the following:
public class TestCandy2 {
public static void main(String[] args) {
UnfairCandyDistributor mean = new UnfairCandyDistributor();
mean.nextCandy(); // 1 for you.
mean.nextCandy(); // 1 for me.
mean.nextCandy(); // 2 for you.
mean.nextCandy(); // 1 for me.
mean.nextCandy(); // 2 for me.
mean.nextCandy(); // 3 for you.
mean.nextCandy(); // 1 for me.
mean.nextCandy(); // 2 for me.
mean.nextCandy(); // 3 for me.
Here The class I have made so far:
public class UnfairCandyDistributor {
private int you;
private int me;
private int extra;
public void nextCandy()
{
if (you != me || extra != you - 1)
{
me++;
System.out.println(me + " for me");
}
else
{
you++;
System.out.println(you + " for you");
extra = 0;
}
}
}
Can't you just add a boolean variable that tells you who to dole out candy to?
public class UnfairCandyDistributor {
private int you = 0;
private int me = 0;
private boolean candyToMe = false;
public void nextCandy()
{
if (candyToMe)
{
for (int i=0; i<you; i++) {
System.out.println("one for me");
me++;
}
else
{
System.out.println("one for you");
you++;
}
candyToMe = !candyToMe;
}
}
or
public class UnfairCandyDistributor {
private int you = 0;
private int me = 0;
private boolean candyToMe = false;
public void nextCandy()
{
if (candyToMe)
{
System.out.println(you + " for me");
me += you;
}
else
{
System.out.println("1 for you");
you++;
}
candyToMe = !candyToMe;
}
}
..depending on whether you want the candies doled out one at a time or in hand-fulls where appropriate.

How to get input without pressing enter every time?

I made a simple game(well not really a game yet) in which the player can move in a room 4x20 characters in size. It runs in console.
But in my game loop I want to be able to move around in the room without pressing enter every time I want to move. The player should be able to press w/a/s/d and have the screen update instantly, but I don't know how to do that.
public class Main{
public static void main(String[] args){
MovementLoop();
}
public static void MovementLoop(){
Scanner input = new Scanner(System.in);
int pos=10, linepos=2;
String keypressed;
boolean playing = true;
while(playing == true){
display dObj = new display(linepos, pos);
dObj.drawImage();
keypressed=input.nextLine();
if(keypressed.equals("w")){
linepos -= 1;
}
else if(keypressed.equals("s")){
linepos += 1;
}
else if(keypressed.equals("a")){
pos -= 1;
}
else if(keypressed.equals("d")){
pos += 1;
}
else if(keypressed.equals("q")){
System.out.println("You have quit the game.");
playing = false;
}
else{
System.out.println("\nplease use w a s d\n");
}
}
}
}
public class display{
private String lines[][] = new String[4][20];
private String hWalls = "+--------------------+";
private String vWalls = "|";
private int linepos, pos;
public display(int linepos1, int pos1){
pos = pos1 - 1;
linepos = linepos1 - 1;
}
public void drawImage(){
for(int x1=0;x1<lines.length;x1++){
for(int x2=0;x2<lines[x1].length;x2++){
lines[x1][x2]="#";
}
}
lines[linepos][pos]="O";
System.out.println(hWalls);
for(int x2=0;x2<lines.length;x2++){
System.out.print(vWalls);
for(int x3=0;x3<lines[x2].length;x3++){
System.out.print(lines[x2][x3]);
}
System.out.println(vWalls);
}
System.out.println(hWalls);
}
}
The answer is simple
You can't do that
Because command line environment is different from swing, as swing can do such a thing as it deals with events and object, whereas, command line have no events.
So, maybe it's a right time to leave command line.

Thread missing updates from other threads

I have created three threads in a java program. One is the main program, the others are two classes that extend Thread. The main thread represent a controller for a machine. Another thread is the actuators and the third is the sensors. The controller sets variables in its own class which is read by the actuator thread. The actuator performs certain actions according to the instructions and update its own internal variables. These are in turn read by the sensor thread which reads the actuator variables (representing real world actions) and sets its own internal variables which in turn is read by the controller and we have come full circle. The controller then sets variables according to the new sensed world etc.
The actuators are in a eternal loop sleeping 100 ms in each loop.
The sensors are also in an eternal loop sleeping 20ms per loop.
The system almost works. The main loop will miss the updates from the sensor unless I add a sleep to it as well. My question is now why that is? Even sleep(0) makes the system work. I've placed the statement inside the performJob(Job input) while loop. How does the java main thread without a sleep call act differently than the same thread with?
Concurrency is a fairly new subject to me.
This is the code I am using:
Main:
public class Main {
public static void main(String[] args) {
Controller Press = new Controller();
Press.processUnits(1); // no reset code at the moment, only use 1 at a time
Press.shutdownThreads();
}
}
Controller:
import java.util.LinkedList;
public class Controller extends Thread {
// Constants
static final int STATE_WAITING = 0;
static final int STATE_MOVE_ARMS = 1;
static final int STATE_MOVE_PRESS = 2;
static final int LOADINGARM = 2;
static final int UNLOADINGARM = 1;
static final int NOARM = 0;
static final boolean EXTEND = true;
static final boolean RETRACT = false;
private enum Jobs {
EXTENDRETRACT, ROTATE, MAGNETONOFF, PRESSLOWERRAISE
}
// Class variables
private int currentState;
// Component instructions
private int armChoice = 0;
private boolean bool = false; // on, up, extend / off, down, retract
private boolean[] rotInstr = {false, false}; // {rotate?, left true/right false}
private boolean errorHasOccurred = false;
private boolean pressDir = false;
private Sensors sense = null;
private Actuators act = null;
private LinkedList<Job> queue = null;
// Constructor
public Controller() {
act = new Actuators(0.0f, this);
sense = new Sensors();
act.start();
sense.start();
currentState = STATE_WAITING;
queue = new LinkedList<Job>();
}
// Methods
int[] getArmInstructions() {
int extret = (bool) ? 1 : 0;
int[] ret = {armChoice, extret};
return ret;
}
boolean[] getRotation() {
return rotInstr;
}
int getControllerState() {
return currentState;
}
boolean getPressDirection() {
return pressDir;
}
public boolean processUnits(int nAmount) {
if (run(nAmount)) {
System.out.println("Controller: All units have been processed successfully.");
return true;
} else { // procUnits returning false means something went wrong
System.out.println("Controller: An error has occured. The process cannot complete.");
return false;
}
}
/*
* This is the main run routine. Here the controller analyses its internal state and its sensors
* to determine what is happening. To control the arms and press, it sets variables, these symbolize
* the instructions that are sent to the actuators. The actuators run in a separate thread which constantly
* reads instructions from the controller and act accordingly. The sensors and actuators are dumb, they
* will only do what they are told, and if they malfunction it is up to the controller to detect dangers or
* malfunctions and either abort or correct.
*/
private boolean run(int nUnits) {
/*
Here depending on internal state, different actions will take place. The process uses a queue of jobs
to keep track of what to do, it reads a job, sets the variables and then waits until that job has finished
according to the sensors, it will listen to all the sensors to make sure the correct sequence of events is
taking place. The controller reads the sensor information from the sensor thread which runs on its own
similar to the controller.
In state waiting the controller is waiting for input, when given the thread cues up the appropriate sequence of jobs
and changes its internal state to state move arms
In Move arms, the controller is actively updating its variables as its jobs are performed,
In this state the jobs are, extend, retract and rotate, pickup and drop.
From this state it is possible to go to move press state once certain conditions apply
In Move Press state, the controller through its variables control the press, the arms must be out of the way!
In this state the jobs are press goes up or down. Pressing is taking place at the topmost position, middle position is for drop off
and lower is for pickup. When the press is considered done, the state reverts to move arms,
*/
//PSEUDO CODE:
//This routine being called means that there are units to be processed
//Make sure the controller is not in a blocking state, that is, it shut down previously due to errors
//dangers or malfunctions
//If all ok - ASSUMED SO AS COMPONENTS ARE FAULT FREE IN THIS VERSION
if (!errorHasOccurred) {
//retract arms
currentState = STATE_MOVE_ARMS;
queue.add(new Job(Jobs.EXTENDRETRACT, LOADINGARM, RETRACT));
queue.add(new Job(Jobs.EXTENDRETRACT, UNLOADINGARM, RETRACT));
performWork();
//System.out.println("Jobs added");
//while there are still units to process
for (;nUnits != 0; nUnits--) {
//move the press to lower position, for unloading
currentState = STATE_MOVE_PRESS;
//rotate to pickup area and pickup the metal, also pickup processed
currentState = STATE_MOVE_ARMS;
queue.add(new Job(Jobs.EXTENDRETRACT, LOADINGARM, EXTEND));
queue.add(new Job(Jobs.EXTENDRETRACT, UNLOADINGARM, EXTEND));
performWork();
//retract and rotate
queue.add(new Job(Jobs.EXTENDRETRACT, LOADINGARM, RETRACT));
queue.add(new Job(Jobs.EXTENDRETRACT, UNLOADINGARM, RETRACT));
performWork();
//state change, press moves to middle position
currentState = STATE_MOVE_PRESS;
//state change back, put the metal on the press, drop processed and pull arms back
currentState = STATE_MOVE_ARMS;
queue.add(new Job(Jobs.EXTENDRETRACT, LOADINGARM, EXTEND));
queue.add(new Job(Jobs.EXTENDRETRACT, UNLOADINGARM, EXTEND));
queue.add(new Job(Jobs.EXTENDRETRACT, LOADINGARM, RETRACT));
queue.add(new Job(Jobs.EXTENDRETRACT, UNLOADINGARM, RETRACT));
performWork();
//state change, press the metal in upper position
currentState = STATE_MOVE_PRESS;
//repeat until done
}
//unload final piece
//move the press to lower position for unload
//rotate and pickup processed piece
//drop it off at unloading and wait for more orders
currentState = STATE_WAITING;
}
return true;
}
private boolean performWork() {
while (!queue.isEmpty()) {
performJob(queue.removeFirst());
}
return true;
}
private boolean performJob(Job input) {
//The purpose of this function is to update the variables and wait until they are completed
// read in the job and check appropriate sensors
boolean[] data = sense.getSensorData(); // LExt, LRet, UlExt, UlRet
printBools(data);
int Instruction = input.Instruction;
boolean skipVars = false;
if (input.Job == Jobs.EXTENDRETRACT) {
if (currentState != STATE_MOVE_ARMS){
System.out.println("Wrong state in performJob. State is "+currentState+" expected "+STATE_MOVE_ARMS);
return false;
}
if ((Instruction == LOADINGARM) && (input.Bool)) skipVars = data[0];
if ((Instruction == LOADINGARM) && (!input.Bool)) skipVars = data[1];
if ((Instruction == UNLOADINGARM) && (input.Bool)) skipVars = data[2];
if ((Instruction == UNLOADINGARM) && (!input.Bool)) skipVars = data[3];
}
if (!skipVars) {
// if sensors not at intended values, update correct variables
System.out.println("Controller: Did not skip vars");
switch (input.Job) {
case EXTENDRETRACT:
armChoice = (Instruction == LOADINGARM) ? LOADINGARM : UNLOADINGARM;
bool = input.Bool;
break;
case ROTATE:
break;
case MAGNETONOFF:
break;
case PRESSLOWERRAISE:
break;
default:
System.out.println("Default called in performJob()");
break;
}
}
// listen to sensors until completed
boolean done = false;
System.out.println("Waiting for sensor data.");
//System.out.print("Instruction is "+Instruction+" and bool is "); if (input.Bool) System.out.print("true\n"); else System.out.print("false\n");
while (!done) {
data = sense.getSensorData();
// REMOVING THIS TRY STATEMENT BREAKS THE PROGRAM
try {
Thread.currentThread().sleep(10);
} catch (InterruptedException e) {
System.out.println("Main thread couldn't sleep.");
}
// Check appropriate sensors
if (input.Job == Jobs.EXTENDRETRACT) {
if ((Instruction == LOADINGARM) && (input.Bool)) done = data[0];
if ((Instruction == LOADINGARM) && (!input.Bool)) done = data[1];
if ((Instruction == UNLOADINGARM) && (input.Bool)) done = data[2];
if ((Instruction == UNLOADINGARM) && (!input.Bool)) done = data[3];
}
}
// reset all variables
armChoice = 0;
bool = false;
// when done return
System.out.println("Finished "+input.Job);
return true;
}
public void shutdownThreads() {
sense.shutDown();
act.shutDown();
}
private class Job {
// Class variables
Jobs Job;
int Instruction;
boolean Bool; // used for directions, up/down, left/right, extend/retract
// Constructor
Job(Jobs newJob, int newInstruction, boolean dir) {
Job = newJob;
Instruction = newInstruction;
Bool = dir;
}
}
private void printBools(boolean[] input) {
System.out.println();
for (int i = 0; i < input.length; i++) {
if (input[i]) System.out.print("true "); else System.out.print("false ");
}
System.out.println();
}
}
Actuators:
public class Actuators extends Thread {
// Constants
private final int ARM = 0, ROTATE = 0; // array indexes - which arm, rotate yes/no?
private final int DIR = 1, ROTDIR = 1; // array indexes - which direction ext/ret, rotate direction
private final int EXT = 1;//, RET = 0;
private final double ARM_SPEED = 5.0;
// Class variables
private Controller Owner = null;
private boolean run = true;
// Constructor
Actuators(float nPos, Controller Owner) {
Reality.changeAngle(nPos);
this.Owner = Owner;
}
// Methods
private void rotate(boolean dir) {
float nAngle = dir ? 0.1f : -0.1f;
Reality.changeAngle(nAngle);
}
public void run() {
while (run) {
try {
sleep(100);
} catch (InterruptedException e) {
System.out.println("Actuators couldn't sleep");
}
// read variables in controller
int nState = Owner.getControllerState();
if (nState == Controller.STATE_MOVE_ARMS) {
boolean[] rot = Owner.getRotation();
if (rot[ROTATE]) { // Rotation?
rotate(rot[ROTDIR]);
} else { // or arm extensions
int[] instr = Owner.getArmInstructions();
if (instr[ARM] != Controller.NOARM) { // 0 = no arm movement
//System.out.println("Actuator arm is "+instr[ARM]);
double dir = (instr[DIR] == EXT) ? ARM_SPEED : -ARM_SPEED; // 1 = extend, 0 = retract
Reality.changeArmLength(instr[ARM], dir);
}
}
}
}
}
void shutDown() {
run = false;
}
}
Reality is a class composed of static fields and methods, written to by the actuators and read by sensors.
public class Reality {
// Constants
static private final double EXTEND_LIMIT = 100.0;
static private final double RETRACT_LIMIT = 0.0;
// Variables
private static float ArmsAngle = 0.0f;
// Read by Sensor
static double LoadingArmPos = 0.0;
static double UnloadingArmPos = 0.0;
// Methods
static void changeAngle(float newAngle) {
ArmsAngle = ArmsAngle + newAngle;
if ((ArmsAngle < 0.0f) || (ArmsAngle > 90.0f))
System.out.println("Reality: Unallowed Angle");
}
static void changeArmLength(int nArm, double dPos) { // true = extend, false = retract
switch (nArm) {
case Controller.LOADINGARM:
LoadingArmPos += dPos;
checkArmPos(LoadingArmPos);
break;
case Controller.UNLOADINGARM:
UnloadingArmPos += dPos;
checkArmPos(UnloadingArmPos);
break;
default:
System.out.println("Arm other than 2 (load) or 1 (unload) in changeArmLength in Reality");
break;
}
}
static float senseAngle() {
return ArmsAngle;
}
static private boolean checkArmPos(double dPos) {
// Allowed positions are 100.0 to 0.0
if ((dPos > EXTEND_LIMIT) || (dPos < RETRACT_LIMIT)) {
System.out.println("Arm position impossible in reality. Is "+dPos);
return true;
} else {
return false;
}
}
}
Finally the sensors:
public class Sensors extends Thread {
// Constants
private final double EXTENDED = 100.0;
private final double RETRACTED = 0.0;
private final double MARGIN = 0.1;
// Class Variables
private boolean run = true;
// Read by Controller
private boolean LoadingExtended = true;
private boolean LoadingRetracted = true;
private boolean UnloadingExtended = true;
private boolean UnloadingRetracted = true;
// Constructor
Sensors() {
LoadingExtended = false;
LoadingRetracted = true;
UnloadingExtended = false;
UnloadingRetracted = true;
}
// Methods
boolean senseLoadingExtended() {
return (Math.abs(Reality.LoadingArmPos - EXTENDED) < MARGIN);
}
boolean senseLoadingRetracted() {
return (Math.abs(Reality.LoadingArmPos - RETRACTED) < MARGIN);
}
boolean senseUnloadingExtended() {
return (Math.abs(Reality.UnloadingArmPos - EXTENDED) < MARGIN);
}
boolean senseUnloadingRetracted() {
return (Math.abs(Reality.UnloadingArmPos - RETRACTED) < MARGIN);
}
// called by Controller
boolean[] getSensorData() {
boolean[] ret = {LoadingExtended, LoadingRetracted, UnloadingExtended, UnloadingRetracted};
return ret;
}
// Sensor primary loop
public void run() {
while (run) {
try {
sleep(20);
}
catch (InterruptedException e) {
System.out.println("Sensors couldn't sleep");
}
LoadingExtended = senseLoadingExtended();
LoadingRetracted = senseLoadingRetracted();
UnloadingExtended = senseUnloadingExtended();
UnloadingRetracted = senseUnloadingRetracted();
}
}
void shutDown() {
run = false;
}
}
Not all fields and functions are read in this version. The program is a reworking of a previous single thread application mostly using function calls. I've cleaned up the code a bit for readability. Constructive design remarks are welcome even though it was not the original question. There is something really fishy going on. I am usually not a superstitious coder but I can for example replace the sleep call with a System.out.println() call and the program will work.
Google for 'Producer consumer queue'.
Don't use sleep() for inter-thread comms unless you want latency, inefficiency and lost data. There are much better mechanisms available that avoid sleep() and trying to read valid data directly from some shared/locked object.
If you load up 'comms' objects with commands/requests/data, queue them off to other threads and immediately create another comms object for subsequent communication, your inter-thread comms will be fast and safe, no sleep() latency and no chance of any thread reading data that is stale or being changed by another thread.
What occurred here was most probably a Memory Consistency Error. When the controller class set the internal control variables and then entered the loop waiting for sensors it most likely prevented the Actuators and Sensors classes from properly updating the readings seen to the controller and as such prevented the controller from seeing the correct values. By adding the synchronize statement to all functions which read from another class the problem was solved. I can only speculate that the sleep call had the controller thread enter a synchronized block of some kind which let the other threads' changes to the variables become visible.
Which JVM are you using?
As fast workaround you can set volatile for fields that shared between threads.
Also please look to actors' approach for messaging: http://doc.akka.io/docs/akka/snapshot/java/untyped-actors.html

Categories