I want to make a plane (Thread) fly from one airfield to another. When a plane is starting the airfield is blocked for 5 sec. (if another plane wants to land or take off - must wait). If a plane reach its destination it lands (if airfield is not blocked by another plane) and then takes a random airfield and fly there and so on....
I have questions in comments - how to make a thread wait ? And what else is wrong with my code ?
Here is my class Samolot aka Plane:
public class Samolot extends Thread{
int id;
double paliwo;
Lotnisko source; //Lotnisko aka airfield
Lotnisko dest;
double xPosition;
double yPosition;
double xTarget;
double yTarget;
public Samolot(Lotnisko source, Lotnisko dest) {
this.source = source;
this.dest = dest;
paliwo = 100;
}
public void run(){
while(true){
tryStart();
}
}
public void tryStart(){
if(source.pas == true){ // if true the airfield is not blocked and we can go
source.timer(); // its a method in class Lotnisko, makes pas = false for 8sec
lecimy(source, dest);
}
else if(source.pas == false){
// how to make a thread wait ?
}
}
public void tryLadowanie(){
if(dest.pas == true){
dest.timer();
source = dest;
dest = Rand(source);
tryStart();
}
else if(dest.pas == false){
//how to make a thread wait ?
}
}
public void lecimy(Lotnisko source, Lotnisko dest){
xPosition = source.coords.getX();
yPosition = source.coords.getY();
xTarget = dest.coords.getX();
yTarget = dest.coords.getY();
while( (xPosition != xTarget) && (yPosition != yTarget) ){
update();
try{
sleep(100);// ok
}
catch (InterruptedException e) {
System.out.println("Error");
}
}
tryLadowanie();
}
public void update() {
paliwo -= 0.05;
double dx = xTarget - xPosition;
double dy = yTarget - yPosition;
double length = sqrt(dx*dx+dy*dy);
dx /= length;
dy /= length;
if (Math.abs(dest.coords.getX() - source.coords.getX()) < 1)
dx = 0;
if (Math.abs(dest.coords.getY() - source.coords.getY()) < 1)
dy = 0;
xPosition += dx;
yPosition += dy;
}
public Point getPositions() {
Point curPos = new Point((int)xPosition, (int)yPosition);
return curPos;
}
OK, so your plane is a thread and your airfields are the shared resource. So to make your plane (thread) wait, you'll need to synchronized on the shared resource (airfield). You'll probably do something like this.
For take off,
public void tryStart() {
synchronized(source) { // try to obtain source lock
try {
Thread.sleep(5000); // lock it for 5 seconds.
}
catch(Exception ignore) {
// You'll need to decide what to do if something interrupts the thread while it's "sleeping" (ie. locked) on the source airfield. Normally, this should not happen.
}
}
// After 5 seconds, releases lock on airfield "source" and Plane starts flying
}
For landing,
public void tryLadowanie() {
synchronized(dest) { // try to obtain dest lock
// successfully obtained lock.
// perform your landing
}
// plane landed and releases "dest" resource for other planes (ie. threads)
}
For a more complete picture of plane flying.
public void run(){
while(true){
tryStart(); // take off from source
lecimy(); // fly the plane. Method will only return when plane reaches destination.
tryLadowanie(); // land the plane
source = dest;
dest = Rand(source); // returns a new destination but can't be the same as source
}
}
public void tryStart(){
synchronized(source) {
try {
Thread.sleep(5000);
}
catch(Exception ignore) { }
}
}
public void tryLadowanie(){
synchronized(dest) {
// land the plane
}
}
Not a complete answer but wait method is used to wait the thread and notify is used to wake up the thread that is in wait.
Check this for more info on wait and notify method:
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#wait()
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#notify()
Use general java object exp.
Object lock=new Object();
To wait :
Synchronized(lock)
{
lock.wait();
}
To release or free the lock from another thread
On same lock object
Synchronized(lock)
{
lock.notify();
}
Related
I am writing Java program which allows me to get the geometric center of random-generated 2-dimensional points. I want the calculations to be done by custom number of threads. I want to suspend/continue calculations at any time. Unfortunately, my code doesn't work, It seems like run() is never executed. Here is what I got:
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
System.out.println("running... " + Thread.currentThread().getName());
PointInterface p = pg.getPoint(); // getting random point(x,y)
pointCount++;
int[] pos = p.getPositions(); // getting (x,y)
System.out.println(pos[0] + ", " + pos[1] + " k");
sumxy[0] += pos[0];
sumxy[1] += pos[1];
geometricCenter[0] = (double) sumxy[0] / pointCount;
geometricCenter[1] = (double) sumxy[1] / pointCount;
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("exception caught in run()");
return;
}
}
}
Setting number of threads:
public void setNumberOfThreads(int threads) {
threadsList.clear();
for (int i = 0; i < threads; i++) {
threadsList.add(new Thread());
}
}
Starting the calculations:
public void start() {
try {
for (Thread t : threadsList) {
t.start();
}
} catch (Exception e) {
System.out.println("start() exception caught");
}
}
Suspending calculations:
public void suspendCalculations() {
try {
Thread.sleep(1200);
} catch (InterruptedException e) {
System.out.println("SuspendCalculations() exception caught");
}
}
Resuming calculations:
I don't exactly know what I'm supposed to do here. Should I create new set of Threads like that?
public void continueCalculations() {
int x = threadsList.size();
threadsList.clear();
for (int i = 0; i < x; i++) {
threadsList.add(new Thread());
threadsList.get(i).start();
}
}
How I run my program:
public static void main(String[] args) {
ParallelCalculations pc = new ParallelCalculations(); // My main class object where run() and all the methods above are declared
PointGenerator g = new PointGenerator(); // class that allows me to generate points
PointInterface a = g.getPoint(); // getting random point
pc.setNumberOfThreads(3);
pc.setPointGenerator(g);
pc.start();
pc.suspendCalculations();
System.out.println(pc.getGeometricCenter()[0] + ", " + pc.getGeometricCenter()[1]);
pc.continueCalculations();
pc.suspendCalculations();
System.out.println(pc.getGeometricCenter()[0] + ", " + pc.getGeometricCenter()[1]);
}
If needed:
Point:
class Point {
public static final int MAX_POSITION = 16;
private int[] positions = new int[2];
Point(int _x, int _y) {
this.positions[0] = _x;
this.positions[1] = _y;
}
public int[] getPositions() {
return positions;
}
}
Point Generator:
class PointGenerator {
private int x = (int) (Math.random() * (Point.MAX_POSITION + 1));
private int y = (int) (Math.random() * (Point.MAX_POSITION + 1));
public PointInterface getPoint() { // Can be called by many Threads at the same time.
return new Point(x, y);
}
}
Your run() should be executed and should do it's thing.
Though there is a far bigger cause for random behaviour in this code: All the threads write to sumxy, geometricCenter and pointCount at he same time without any syncronisation-locks, causing more or less random behaviour. You at least need to implement some kind of synchronisation to prevent simultanious writes.
Maybe start here (Java synchonized tutorial by Oracle) if you have no clue.
But simply adding synchronisation to everything will probably just make it slower than a single thread, you will need some kind of buffer for each thread to work independently and than collect the results when they are suspended.
And now general problems:
A) Your suspendCalculations() doesn't do anything (for 1200ms to be percise). To break the calcualtion you would need to interrupt all the worker-threads since they terminate upon interruption. Call threadsList.get(i).Interrupt() to do so.
B) If you want to to be able to change the number of threads while suspended, this is a way to go. If this is not necessarry, it would be more efficient to create a constant
public static final Object LOCK = new Object();
make all the threads LOCK.wait() on that object, so resuming them is just a call to LOCK.notifyAll().
C) Instead of using your own implementaion of Point you can use java.awt.Point.
D) Returning the coordinates of a point simply in an array is really bad for readability of your code, java.awt.Point has getX() and getY() functions.
I'm having an issue and I'm not certain if it's recursion-based. I created a GUI maze that solves itself but the curser jumps over any recursion-traveled square instead of re-traveling the square. Even though it ultimately finds the goal, I want to show it's entire path but I can't stop the curser from jumping around.
I'm using Runnable to track the maze in real-time so I can see it bounce but without the recursion-travel keeping it bound, the recursive functions cease to work (it just bounces back and forth which, again, I don't quite understand.) I started java about three months ago in an accelerated program so I'm not sure if the issue is my understanding of recursion, or a simple addition to a method, or if I'll have to rewrite a large portion of code.
I included the whole code just in case but really it's an issue that's within the travel method or the visited method. Would the answer be to write an entirely new method that re-travels the changed "visited" string maze? I've been struggling with this for a bit and I just need some direction toward an answer.
import java.awt.*;
import javax.swing.*;
class extraCreditMaze extends JPanel implements Runnable { //uses Runnable to execute jPanel
private String [][] ratMaze = //string maze
{{"blocked","blocked","blocked","blocked","blocked","blocked","blocked","blocked"},
{"blocked","open","blocked","blocked","blocked","blocked","blocked","blocked"},
{"blocked","open","open","open","open","open","open","blocked"},
{"blocked","blocked","open","blocked","open","blocked","open","blocked"},
{"blocked","blocked","open","blocked","open","blocked","open","goal"},
{"blocked","open","open","open","blocked","open","open","blocked"},
{"blocked","blocked","blocked","open","open","open","blocked","blocked"},
{"blocked","blocked","blocked","blocked","blocked","blocked","blocked","blocked"}};
final private int SquareSize = 15;
final private int BoardSize = 17;
private boolean free = false;
int axisX = 1, axisY = 1;
public void paintComponent(Graphics color) //paint components for char
{
super.paintComponent(color);
for(int row = 0; row < ratMaze.length; row++)
{
for(int col = 0; col< ratMaze.length; col++)
{
if(row==axisX && col==axisY) //traveling curser = blue
{
color.setColor(Color.blue);
color.fillOval(col*15,row*15,15,15);
}
else if(ratMaze[row][col]=="blocked") //empty = black
{
color.setColor(Color.black);
color.fillRect(col*SquareSize,row*SquareSize,BoardSize,BoardSize);
}
else if(ratMaze[row][col]=="goal")
{
color.setColor(Color.red); //goal = red
color.fillOval(col*15,row*15,15,15);
}
else if(ratMaze[row][col]=="visited")
{
color.setColor(Color.green); //path traveled = green
color.fillOval(col*15,row*15,15,15);
}
else
{
color.setColor(Color.white); //empty space = white
color.fillRect(col*SquareSize,row*SquareSize,BoardSize,BoardSize);
}
}
}
}
public void run () //starts run at (1,1)
{
travel(1,1);
}
public boolean goal(int x, int y){ //method to check goal (true/false)
if(ratMaze[x][y]=="goal")
return true;
else
return false;
}
public void changedVisited(int x, int y) //method to change traveled
{
ratMaze[x][y] = "visited";
axisX = x;
axisY = y;
}
public boolean boundaries(int x, int y) //check boundaries
{
if(ratMaze[x][y]=="blocked")
return true;
else
return false;
}
public boolean visited(int x, int y) //check if visited
{
if(ratMaze[x][y]=="visited")
return true;
else
return false;
}
private void travel(int x, int y)
{
if(boundaries(x,y)) //makes sure it's within bounds
return;
if(visited(x,y)) //makes sure it hasn't already been visited
return;
if(goal(x,y)) //checks if it's the goal/changes boolean
{
free = true;
JOptionPane.showMessageDialog(this, "You did it, Dr. Cui!"); //fun message!
}
if(!free) //all recursion functions if free=false
{
changedVisited(x,y); //changes traveled block to "visited"
repaint(); //repaints visited
try {Thread.sleep(300); } catch (Exception e) { }//slows down the traveling curser
//I do not understand catch (Exception e)
travel(x-1,y); //recursive travel functions
travel(x+1,y);
travel(x,y-1);
travel(x,y+1);
}
}
}
public class runExtraCreditMaze {
public static void main (String [] args) { //JFrame panel and perimeters
JFrame output = new JFrame();
output.setSize(115, 150);
output.setTitle("The Rat Maze");
output.setLocationRelativeTo(null);
extraCreditMaze Maze = new extraCreditMaze();
output.setContentPane(Maze);
output.setVisible(true);
Thread runnable = new Thread(Maze); //Creates Runnable thread for Maze object
runnable.start(); //Starts Runnable thread of Maze object
}
}
Problem is, as you wrote with the "visited". You are missing an decision tree on what to do, when there is no valid move and you are not in the goal. You will need to allow your rat to back track itself. You will probably need to "free" the visited cells when returning from no valid move.
I will try to add some code samples when I get to IDE :)
update: this is very badly written, and it is a bit lagging. but it should work. It needs a bit of cleaning and verification... I reused your boolean variable, which is bad .. :) and switched the true/false. I will do a bit of cleaning up tomorrow just to leave a nicer answer, but I think you will manage to understand what is going on.
update2:I have cleaned it a bit. Important lessons here are as follows:
1) backtracking needs to be done when all 4 steps fails. When your rat have nowhere to go, you need to disqualify the cell from your shortest path (ratMaze[x][y]="open")
2) You need to change position of your rat, when you return from recursion call, but before you continue with next step into. You will also need to let your program know that you are returning from recursion (thus the isBacktracking)
private void repaintMaze(int x, int y) {
changedVisited(x, y); //changes traveled block to "visited"
repaint(); //repaints visited
isBacktracking = false;
try {
Thread.sleep(500);
} catch (Exception e) {
}
}
private boolean travel(int x, int y) {
if (goal(x, y)) //checks if it's the goal/changes boolean
{
JOptionPane.showMessageDialog(this, "You did it, Dr. Cui!");//fun message!
return true;
}
if (boundaries(x, y) || visited(x, y)) //makes sure it's within bounds
return false;
repaintMaze(x, y);
boolean result; //recursive travel functions
result = travel(x - 1, y);
if (result) {
return true;
}
if (isBacktracking) {
repaintMaze(x, y);
}
result = travel(x + 1, y);
if (result) {
return true;
}
if (isBacktracking) {
repaintMaze(x, y);
}
result = travel(x, y - 1);
if (result) {
return true;
}
if (isBacktracking) {
repaintMaze(x, y);
}
result = travel(x, y + 1);
if (result) {
return true;
}
if (isBacktracking) {
repaintMaze(x, y);
}
ratMaze[x][y] = "open";
isBacktracking = true;
return false;
}
you should also add exit on close to your JFrame :) It will stop the application once you click the X button on the window itself
output.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
I have a matrix that implements John Conway's life simulator in which every cell represents either life or lack of it.
Every life cycle follows these rules:
Any live cell with fewer than two live neighbors dies, as if caused by under-population.
Any live cell with two or three live neighbors lives on to the next generation.
Any live cell with more than three live neighbors dies, as if by overcrowding.
Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction.
Every cell will have a thread that will perform the changes by the rules listed above.
I have implemented these classes:
import java.util.Random;
public class LifeMatrix {
Cell[][] mat;
public Action currentAction = Action.WAIT_FOR_COMMAND;
public Action changeAction;
public enum Action {
CHECK_NEIGHBORS_STATE,
CHANGE_LIFE_STATE,
WAIT_FOR_COMMAND
}
// creates a life matrix with all cells alive or dead or random between dead or alive
public LifeMatrix(int length, int width) {
mat = new Cell[length][width];
for (int i = 0; i < length; i++) { // populate the matrix with cells randomly alive or dead
for (int j = 0; j < width; j++) {
mat[i][j] = new Cell(this, i, j, (new Random()).nextBoolean());
mat[i][j].start();
}
}
}
public boolean isValidMatrixAddress(int x, int y) {
return x >= 0 && x < mat.length && y >= 0 && y < mat[x].length;
}
public int getAliveNeighborsOf(int x, int y) {
return mat[x][y].getAliveNeighbors();
}
public String toString() {
String res = "";
for (int i = 0; i < mat.length; i++) { // populate the matrix with cells randomly alive or
// dead
for (int j = 0; j < mat[i].length; j++) {
res += (mat[i][j].getAlive() ? "+" : "-") + " ";
}
res += "\n";
}
return res;
}
public void changeAction(Action a) {
// TODO Auto-generated method stub
currentAction=a;
notifyAll(); //NOTIFY WHO??
}
}
/**
* Class Cell represents one cell in a life matrix
*/
public class Cell extends Thread {
private LifeMatrix ownerLifeMat; // the matrix owner of the cell
private boolean alive;
private int xCoordinate, yCoordinate;
public void run() {
boolean newAlive;
while (true) {
while (! (ownerLifeMat.currentAction==Action.CHECK_NEIGHBORS_STATE)){
synchronized (this) {//TODO to check if correct
try {
wait();
} catch (InterruptedException e) {
System.out.println("Interrupted while waiting to check neighbors");
}}
}
// now check neighbors
newAlive = decideNewLifeState();
// wait for all threads to finish checking their neighbors
while (! (ownerLifeMat.currentAction == Action.CHANGE_LIFE_STATE)) {
try {
wait();
} catch (InterruptedException e) {
System.out.println("Interrupted while waiting to change life state");
};
}
// all threads finished checking neighbors now change life state
alive = newAlive;
}
}
// checking the state of neighbors and
// returns true if next life state will be alive
// returns false if next life state will be dead
private boolean decideNewLifeState() {
if (alive == false && getAliveNeighbors() == 3)
return true; // birth
else if (alive
&& (getAliveNeighbors() == 0 || getAliveNeighbors() == 1)
|| getAliveNeighbors() >= 4)
return false; // death
else
return alive; // same state remains
}
public Cell(LifeMatrix matLifeOwner, int xCoordinate, int yCoordinate, boolean alive) {
this.ownerLifeMat = matLifeOwner;
this.xCoordinate = xCoordinate;
this.yCoordinate = yCoordinate;
this.alive = alive;
}
// copy constructor
public Cell(Cell c, LifeMatrix matOwner) {
this.ownerLifeMat = matOwner;
this.xCoordinate = c.xCoordinate;
this.yCoordinate = c.yCoordinate;
this.alive = c.alive;
}
public boolean getAlive() {
return alive;
}
public void setAlive(boolean alive) {
this.alive = alive;
}
public int getAliveNeighbors() { // returns number of alive neighbors the cell has
int res = 0;
if (ownerLifeMat.isValidMatrixAddress(xCoordinate - 1, yCoordinate - 1) && ownerLifeMat.mat[xCoordinate - 1][yCoordinate - 1].alive)
res++;
if (ownerLifeMat.isValidMatrixAddress(xCoordinate - 1, yCoordinate) && ownerLifeMat.mat[xCoordinate - 1][yCoordinate].alive)
res++;
if (ownerLifeMat.isValidMatrixAddress(xCoordinate - 1, yCoordinate + 1) && ownerLifeMat.mat[xCoordinate - 1][yCoordinate + 1].alive)
res++;
if (ownerLifeMat.isValidMatrixAddress(xCoordinate, yCoordinate - 1) && ownerLifeMat.mat[xCoordinate][yCoordinate - 1].alive)
res++;
if (ownerLifeMat.isValidMatrixAddress(xCoordinate, yCoordinate + 1) && ownerLifeMat.mat[xCoordinate][yCoordinate + 1].alive)
res++;
if (ownerLifeMat.isValidMatrixAddress(xCoordinate + 1, yCoordinate - 1) && ownerLifeMat.mat[xCoordinate + 1][yCoordinate - 1].alive)
res++;
if (ownerLifeMat.isValidMatrixAddress(xCoordinate + 1, yCoordinate) && ownerLifeMat.mat[xCoordinate + 1][yCoordinate].alive)
res++;
if (ownerLifeMat.isValidMatrixAddress(xCoordinate + 1, yCoordinate + 1) && ownerLifeMat.mat[xCoordinate + 1][yCoordinate + 1].alive)
res++;
return res;
}
}
public class LifeGameLaunch {
public static void main(String[] args) {
LifeMatrix lifeMat;
int width, length, populate, usersResponse;
boolean userWantsNewGame = true;
while (userWantsNewGame) {
userWantsNewGame = false; // in order to finish the program if user presses
// "No" and not "Cancel"
width = Integer.parseInt(JOptionPane.showInputDialog(
"Welcome to John Conway's life simulator! \n"
+ "Please enter WIDTH of the matrix:"));
length = Integer.parseInt(JOptionPane.showInputDialog(
"Welcome to John Conway's life simulator! \n"
+ "Please enter LENGTH of the matrix:"));
lifeMat = new LifeMatrix(length, width);
usersResponse = JOptionPane.showConfirmDialog(null, lifeMat + "\nNext cycle?");
while (usersResponse == JOptionPane.YES_OPTION) {
if (usersResponse == JOptionPane.YES_OPTION) {
lifeMat.changeAction(Action.CHECK_NEIGHBORS_STATE);
}
else if (usersResponse == JOptionPane.NO_OPTION) {
return;
}
// TODO leave only yes and cancel options
usersResponse = JOptionPane.showConfirmDialog(null, lifeMat + "\nNext cycle?");
}
if (usersResponse == JOptionPane.CANCEL_OPTION) {
userWantsNewGame = true;
}
}
}
}
My trouble is to synchronize the threads:
Every cell(a thread) must change its life/death state only after all threads have checked their neighbors. The user will invoke every next life cycle by clicking a button.
My logic, as can be understood from the run() method is to let every cell(thread) run and wait for the right action state that is represented by the variable currentAction in LifeMatrix class and go ahead and execute the needed action.
What I struggle with is how do I pass these messages to the threads to know when to wait and when execute next action?
Any suggestions to change the design of the program are very welcome as long as every cell will be implemented with a separate thread!
Using a CyclicBarrier should be easy to understand:
(updated to use 2 Barriers, and make use of inner class to make cell looks shorter and cleaner)
psuedo code:
public class LifeMatrix {
private CyclicBarrier cycleBarrier;
private CyclicBarrier cellUpdateBarrier;
//.....
public LifeMatrix(int length, int width) {
cycleBarrier = new CyclicBarrier(length * width + 1);
cellUpdateBarrier = new CyclicBarrier(length * width);
// follow logic of old constructor
}
public void changeAction(Action a) {
//....
cycleBarrier.await()
}
// inner class for cell
public class Cell implements Runnable {
// ....
#Override
public void run() {
while (...) {
cycleBarrier.await(); // wait until start of cycle
boolean isAlive = decideNewLifeState();
cellUpdateBarrier.await(); // wait until everyone completed
this.alive = isAlive;
}
}
}
}
I would solve this using two Phasers.
You use one Phaser to control cycles and one one to synchronize the cells when they determine if they are alive or not.
public class Cell extends Thread {
private LifeMatrix ownerLifeMat; // the matrix owner of the cell
private boolean alive;
private int xCoordinate, yCoordinate;
// Phaser that controls the cycles
private Phaser cyclePhaser;
// Phaser for cell synchronisation
private Phaser cellPhaser;
public Cell(LifeMatrix matLifeOwner, Phaser cyclePhaser, Phaser cellPhaser,
int xCoordinate, int yCoordinate, boolean alive) {
this.ownerLifeMat = matLifeOwner;
this.cyclePhaser = cyclePhaser;
this.cellPhaser = cellPhaser;
this.xCoordinate = xCoordinate;
this.yCoordinate = yCoordinate;
this.alive = alive;
// Register with the phasers
this.cyclePhaser.register();
this.cellPhaser.register();
}
public void run() {
boolean newAlive;
while (true) {
// Await the next cycle
cyclePhaser.arriveAndAwaitAdvance();
// now check neighbors
newAlive = decideNewLifeState();
// Wait until all cells have checked their state
cellPhaser.arriveAndAwaitAdvance();
// all threads finished checking neighbors now change life state
alive = newAlive;
}
}
// Other methods redacted
}
You control the cycles by having the main thread register on the cyclePhaser
and have it arrive on it to start the next cycle.
i have a problem with one thing. I have a map of 10 cities and a civilian. I want the civilian to be walking from city to city randomly. But the problem is that the city is beeing chosen on and on so the civilian is changing the destination before he reachs it. This is my part of a code of a Jpanel where everything is drawn:
#Override
public void run() {
while (running) {
update();
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException ex) {
}
}
}
private void update() {
if (game != null && running == true) {
c.goTo(cities); // c is civilian
}
}
and this is part of code for civilian
private boolean set = true;
public void move(int x, int y) {
if (this.location.x != x || this.location.y != y) {
if (this.location.x > x) {
this.location.x -= 1;
} else {
this.location.x += 1;
}
if (this.location.y > y) {
this.location.y -= 1;
} else {
this.location.y += 1;
}
}
}
public void goTo(ArrayList<City> cities) {
City city;
if (set) {
city = cities.get(rand());
move(city.location.x, city.location.y);
set = false;
} else {
set = true;
}
}
public int rand() {
int i;
Random rand = new Random();
i = rand.nextInt(10);
return i;
}
How to solve it ?
So, your problem is here:
while (running) {
update();
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException ex) {
}
}
You're calling update every 17 milliseconds which in turn is causing your civilian to move to a new city every 17 milliseconds. You could make a separate statement that calls update while another boolean statement is false so that you travel only when he is in a city.
For example:
boolean travelling = //whatever you go about to configure this
while(travelling == false){
update();
}
This will cause him to only travel when he is not in a city. Here is some very rough code (you will have to configure it to your liking):
//civilian x //civilian y
if(this.location.x == //randomed city.x && this.location.y == //randomed city.y){
travelling = false;
}
This will most likely need to be within the run() method in your first set of code, so it can be checked over and over. But let me explain what the above code is doing:
First, you have a thread or something keeping it running checking if your civilian's x and y correspond to the most recently randomed city's x and y, obviously when they're the same, the civilian is at the city.
Second, when the x and y's are the same, the statement makes travelling false
Third, When travelling is false, your custom update method is called, picking a new city, at random and putting your civilian back on the move.
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