How to "queue" the same thread? - java

I'm building a elevator simulator using sliders. I need the "elevators" to move at the same time, so I thought of using threads, but my knowledge is basic on this topic. ;) I got the elevators to move via threads (see code below) but I'm stuck on the option to move a specific elevator to one floor (e.g. from floor 4 to floor 10) AND THEREAFTER TO ANOTHER FLOOR (e.g. floor 1) If I just create the threads, the elevator tries to move in both directions simultaneously! So I tried to check if the thread name existed already, and then it will only move in one direction. Problem is that it then ignores the second command to move in the other direction. I assume that it has to do with the fact that the thread name still exists, or maybe that the code execution has moved past the second 'command' to move to floor 1? Please help!
private void btnResetActionPerformed(java.awt.event.ActionEvent evt) {
moveLift(1, 10); //moves lift 1 to floor 10
moveLift(1, 1); //should move lift 1 to floor 1 from 10
moveLift(2, 10); //moves lift 2 to floor 10
}
private void moveLift(int liftNum, int floorNum) {
boolean b = false;
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread t : threads) {
String name = t.getName();
if (name.equals("Lift" + liftNum)) {
b = true;
}
}
if (!b) {
MyThread mt = new MyThread(liftNum, floorNum);
mt.setName("Lift" + liftNum);
mt.start();
}
}
Any advise on queuing the moveLift commands so the threads don't fight each other?

Related

Implementing a simple turn-based game in Java using the wait-notify approach

I'm trying to implement a word game in Java, where each player takes turns extracting a number of random letters from a set, then trying to create a valid word with those letters. This is what I have so far (simplified for clarity's sake):
In the Game class, I start the game by running a thread for each player (and one for the timekeeper). I want the first player in the activePlayers list (which initially is the same as the players list) to make the first move, so I initialized the turn and turnIndex attributes to correspond to this player:
public void play()
{
this.turn = activePlayers.get(0); //the player who joined first goes first
this.turnIndex = 0; //the player's index in the ArrayList
for(Player player : players) {
new Thread(player).start();
}
new Thread(new Timekeeper()).start(); //keeps track of the game's duration
}
In the Player class, I want the players on stand-by to not do anything, and simply wait for the current player to finish their business, hence the first while loop. Then, when a player's turn has ended, I want that thread to yield the monitor to another player's thread and wait its next turn. This is how I decided to approach it:
private synchronized boolean submitWord() throws InterruptedException
{
while(game.turn != this)
{
System.out.println(this.name + " is waiting their turn...");
wait();
}
Thread.sleep(1000);
List<Tile> extracted = game.getBag().extractTiles(wordLength);
if(extracted.isEmpty())
return false; //if there are no more letters to extract, the thread ends its execution
//game logic goes here - creating and validating the word
//after this player is done, the next player makes their move
game.turnIndex++;
if(game.turnIndex >= game.activePlayers.size())
game.turnIndex = 0;
game.turn = game.activePlayers.get(game.turnIndex);
notifyAll();
return true;
}
#Override
public void run()
{
do {
try {
this.running = this.submitWord();
} catch(InterruptedException e) {
System.out.println("Something went wrong with " + this.name + "...");
e.printStackTrace();
}
} while(this.running);
game.activePlayers.remove(this); //the player is now inactive
if(game.winner == this)
System.out.println("Winner: " + this.name + " [" + this.score + " points]");
}
However, when I try to run the program, I get something like this:
Player 2 is waiting their turn...
Player 3 is waiting their turn...
1 seconds elapsed...
Player 1: AERIAL [36 points]
Player 1 is waiting their turn...
2 seconds elapsed...
3 seconds elapsed...
4 seconds elapsed...
5 seconds elapsed...
6 seconds elapsed...
Basically, the game doesn't move past Player 1's first try, and I get stuck in an infinite loop where nothing happens. Am I not using the wait() and notifyAll() methods properly? How should I make the player threads communicate with each other?
If I have understood your code correctly, that submitWord method belongs to the Player class. The keyword synchronized should be used to obtain the monitor of a shared resource to limit different threads from accessing the same resource at the same time and avoid race conditions.
In your case, you're synchronizing over a Player thread which is not the right design. You should synchronize instead over the shared resource which is the game object in this scenario. Besides, try to use synchronized blocks rather than entire synchronized methods, as the latter are more likely to block.
Within the Player's run method you should check whether the thread can acquire the game resource first with a synchronized block, if they do, then you can check whether it's the Player's turn by confronting the turn index of the game object with the Player's index. If it's not the Player's turn it invokes the wait() method; otherwise it carries on with its task by invoking submitWord.
Here, I've tweaked your code. You forgot a notify (or notifyAll) call when you were returning false in your submitWord method. That might have caused some stuck scenarios when there were no combinations available.
//Now, this method can be called only under the condition the the game's monitor lock has been already acquired. So, it can only be invoked within a synchronized block.
private boolean submitWord() {
List<Tile> extracted = game.getBag().extractTiles(wordLength);
if(extracted.isEmpty()){
//notify is more efficient than notifyAll as it causes less overhead by awakening only one random thread instead of all the ones waiting
this.game.notify();
//you were returning without notifying here... This might have caused some stucking scenarios...
return false;
}
//game logic goes here - creating and validating the word
//Rotating the turn
game.turnIndex = (this.game.turnIndex + 1) % this.game.activePlayers.size();
game.turn = game.activePlayers.get(game.turnIndex);
this.game.notify();
return true;
}
#Override
public void run() {
do {
synchronized(this.game){
if (this.game.indexTurn == this.index){
this.running = this.submitWord();
//It's more efficient to check here whether the player must be removed or not as you already own the game's lock
if (!this.running){
this.game.activePlayers.remove(this);
}
} else {
try {
this.game.wait();
} catch(InterruptedException e) {
System.out.println("Something went wrong with " + this.name + "...");
e.printStackTrace();
}
}
}
} while(this.running);
//you should re-acquire the game's lock here since you're modifying the set of players
//synchronized(this.game){
// this.game.activePlayers.remove(this);
//}
if(this.game.winner == this){
System.out.println("Winner: " + this.name + " [" + this.score + " points]");
}
}
Just a thought, but it could be that the sleep is happening within a synchronized method: Thread.sleep is blocking other thread also, working on other method, along with itself callled inside synchronized method

Why is synchronization not working properly within this code?

Over the past few days I have been reading articles about Multithreading and I have come across a simple task using multhithreading. This is the task:
Create an application which simulates the running race of 50 meters(in my code they are 10, does not matter). The number of runners should be 5 and you should name each runner thread. Print the winner. All the other threads should complete the race, as well. Print the time taken by each runner to complete the race and highlight the winner's time.
This is the code I've written:
public class Racer implements Runnable {
public static String winner;
public static int time = 0;
public void incrementTime() {
synchronized (Racer.class) {
time++;
}
}
public void race() {
for (int distance = 1; distance <= 10; distance++) {
incrementTime();
System.out.println("Distance covered by " + Thread.currentThread().getName() + " is " + distance + " meters.");
boolean finalDest = this.isTheRaceOver(distance);
if (finalDest) {
break;
}
}
}
private boolean isTheRaceOver(int finalDistance) {
boolean isRaceOver = false;
if (Racer.winner == null && finalDistance == 10) {
String winnerName = Thread.currentThread().getName();
Racer.winner = winnerName;
System.out.println("The winner is : " + Racer.winner + " with time " + time);
isRaceOver = true;
} else if (Racer.winner == null) {
isRaceOver = false;
} else if (finalDistance != 10) {
isRaceOver = false;
} else if (finalDistance == 10) {
System.out.println(Thread.currentThread().getName() + " is with time " + time);
}
return isRaceOver;
}
#Override
public void run() {
this.race();
}
}
public class RacerDemo {
public static void main(String[] args) {
Racer racer = new Racer();
Thread a = new Thread(racer, "A");
Thread b = new Thread(racer, "B");
Thread c = new Thread(racer, "C");
Thread d = new Thread(racer, "D");
Thread e = new Thread(racer, "E");
a.start();
b.start();
c.start();
d.start();
e.start();
}
}
One output is:
Distance covered by A is 1 meters.
Distance covered by C is 1 meters.
Distance covered by C is 2 meters.
Distance covered by C is 3 meters.
Distance covered by C is 4 meters.
Distance covered by C is 5 meters.
Distance covered by C is 6 meters.
Distance covered by C is 7 meters.
Distance covered by C is 8 meters.
Distance covered by C is 9 meters.
Distance covered by C is 10 meters.
The winner is : C with time 12 // should be 11 ?
Distance covered by B is 1 meters.
Distance covered by B is 2 meters.
...... and so on
The thing that bothers me is when it prints the time taken by each racer(thread) to cover the distance, it does not show the right time. I made incrementTime() synchronized, but the program does not work properly either. Can you tell me what is wrong? Where is my mistake?
Each runner increments the time, causing an inconsistent state. You should separate the racers from the actual race, which should probably be in a separate class.
Your problem occurs in the race method of the Racer Runnable, where each runner increments the static time field, thus causing the unexpected behavior.
In your implementation, time is shared by all the threads. So, if one thread increments is, the other thread will read that value, e.g.:
Thread 1 enters race() value of time is 0
Thread 1 calls incrementTime() changing the value to 1
Thread 2 enters race() value of time is 1
Thread 2 calls incrementTime() changing the value to 2
This will leave the time variable in an inconsistent state. To avoid this, you can try delaring time inside race() method so that each thread has its own time.
Every runner increments time and there is only a lock on the increments time method. Runner C finishes their race and calls the isRaceOver method. As c is going to get the time of 11, thread b runs the race method, sneaks in and increments time 1. As a result, c gets the time of 12 and prints out the time incorrectly. If your intention is for all runners to be able to increment the time, you have to make sure that only 1 thread is running race or IsTheRaceOver at a time.
You would get same result without synchronized block since you synchronized an integer which is atomic by default. Synchronized keyword is unnecessary so there is no synchronization at all.
Distance covered by A is 1 meters.
Distance covered by C is 1 meters.
Distance covered by C is 2 meters.
...
The winner is : C with time 12 // should be 11 ?
From your output it's clear that another thread was incremented time too. There might be another thread which incremented time right before you print the winner. To solve your problem, you have to synchronize both incrementTime and isTheRaceOver methods this way you will make sure another thread will not be able to increment time right before you print it.
But hold on: Synchronized block does not guarantee updates are visible to another threads which is called cache coherence. If you don't use volatile keywords when one thread updates a variable, it's not guaranteed that another thread will see it. For example even if you set the winner another thread may still see it as null.
Make sure you use volatile keyword or locks (which also use memory barriers) to guarantee that the updates will be visible to other threads.

How to count the number of collisions with collidesWith() in JavaME?

I'm developing a game with JavaME and I need to count the number of collisions in my game.
I'm using the collidesWith() method, and I'm doing something like this:
private void checkCollision()
{
if (spBoy.collidesWith(spBall, true)) {
this.collides++;
if (this.collides == 3) {
//here I will show a Game Over image.
}
}
}
As you can see, if the number of collisions is 3, the game is over, but I can't count the number of collisions, because when I increment this.collides, automatically I have 3 collisions in one time.
I'm assuming you're calling checkCollision() inside your main loop. This means it gets called 30-60 times per second.
If the two sprites doesn't move at all during that second, there will be 30-60 collisions - because it's true in each cycle.
What you wanna do is add a timer where your spBoy sprite can't be hurt.
int safeTimer = 0;
int timeSinceLastLoop; // Add this calculation to your loop
private void checkCollision() {
safeTimer-= timeSinceLastLoop;
if (spBoy.collidesWith(spBall, true) && safeTimer<=0) {
this.collides++;
safeTimer=3000; // Wait 3 seconds till vulnerability
if (this.collides == 3) {
//here I will show a Game Over image.
}
}
}

set a delay in libgdx game

i have a game(like super jumper, this game is a jumping game) that our character has life. after collision with enemies, his life reduce. and i want to after 1 sec , calculate the collisions. i mean in this 1 sec, if my character contact with enemies , nothing happen and he continue his way.
for this , i define a boolean variable in my GameScreen class, name "collision" and another in Wolrd class, name "collBirds". after one contact with enemy collision and collBirds change to true. but i want after 1 sec collistion change to false. i use several things like System.currentTimeMillis() and "for loop",and nothing happen. i'm not so good in java.
this is my condition:
if(World.collBirds == true && collition == false){
life -= 1;
lifeString = "Life : " + life;
World.collBirds = false;
collition = true;
for (??? "need to stay here for 1 sec" ???) {
collition = false;
}
}
In some cases you could also want to use com.badlogic.gdx.utils.Timer
Example usage:
float delay = 1; // seconds
Timer.schedule(new Task(){
#Override
public void run() {
// Do your work
}
}, delay);
When the first collision occurs, set a float timeSinceCollision = 0;
Then each loop, you will need to add the time since last check to the variable, and check if it's more than a second.
timeSinceCollision += deltaTime;
if(timeSinceCollision > 1.0f) {
// do collision stuff
} else {
// ignore the collision
}
If you want to do this in same thread than you can use Thread.sleep(). But in this case your current thread will freeze and if this is single thread game, than your whole game will freeze. If you don't want your game to freeze for 1 second, than you should spawn the thread and in that thread call the sleep and after sleep, change the flag

controlling threads flow

I had a task to write simple game simulating two players picking up 1-3 matches one after another until the pile is gone. I managed to do it for computer choosing random value of matches but now I'd like to go further and allow humans to play the game. Here's what I already have : http://paste.pocoo.org/show/201761/
Class Player is a computer player, and PlayerMan should be human being. Problem is, that thread of PlayerMan should wait until proper value of matches is given but I cannot make it work this way. Logic is as follows: thread runs until matches equals to zero. If player number is correct at the moment function pickMatches() is called. After decreasing number of matches on table, thread should wait and another thread should be notified. I know I must use wait() and notify() but I can't place them right.
Class Shared keeps the value of current player, and also amount of matches.
public void suspendThread() {
suspended = true;
}
public void resumeThread() {
suspended = false;
}
#Override
public void run(){
int matches=1;
int which = 0;
int tmp=0;
Shared data = this.selectData();
String name = this.returnName();
int number = this.getNumber();
while(data.getMatches() != 0){
while(!suspended){
try{
which = data.getCurrent();
if(number == which){
matches = pickMatches();
tmp = data.getMatches() - matches;
data.setMatches(tmp, number);
if(data.getMatches() == 0){
System.out.println(" "+
name+" takes "+matches+" matches.");
System.out.println("Winner is player: "+name);
stop();
}
System.out.println(" "+
name+" takes "+matches+" matches.");
if(number != 0){
data.setCurrent(0);
}
else{
data.setCurrent(1);
}
}
this.suspendThread();
notifyAll();
wait();
}catch(InterruptedException exc) {}
}
}
}
#Override
synchronized public int pickMatches(){
Scanner scanner = new Scanner(System.in);
int n = 0;
Shared data = this.selectData();
System.out.println("Choose amount of matches (from 1 to 3): ");
if(data.getMatches() == 1){
System.out.println("There's only 1 match left !");
while(n != 1){
n = scanner.nextInt();
}
}
else{
do{
n = scanner.nextInt();
}
while(n <= 1 && n >= 3);
}
return n;
}
}
Well, let me first say that I think you are making this hardier than you need to. If it were me, I would create a 'GameMaster' class whose job it is to loop and tell each player when their turn comes up. Your player classes wouldn't have loops, just a takeTurn method. This way you can remove the waiting/notifying behavior from your player classes.
If you wish to keep the design you have, I would still get rid of the wait/notify and use a Semaphore. Check the docs for proper usage, but the gist is that you would remove the suspend/resume methods and have a acquire() call at the top of your loop and release at the bottom. Just make sure fairness is set to true in the constructor, that way you won't have to worry about a player taking two turns in a row by acquiring the semaphore lock twice in a row.
Ok, so I managed to do it without wait() etc.
http://paste.pocoo.org/show/201966/
When you find yourself having to set up communication between threads to synchronize their execution, just so that a specified sequence of events takes place (such as taking turns playing a game), it's a good sign that you may have more threads than you need.
In this case, consider a single thread that executes a takeTurn() method on various extensions of a Player class might make life easier for you. You could make Player an abstract base class that mandates .takeTurn(), then have HumanPlayer and MachinePlayer classes encapsulate the code that makes sense for each type of player inside that method. This should make extension to larger numbers of players relatively trivial as compared to lots of wait() and notify().

Categories