controlling threads flow - java

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().

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

How to wait in java without stopping the entire program

I am making a game where the player can throw up to three projectiles at a time. I'm having trouble with the reloading. Here is the code:
public class AmmoManager {
public void tick(){
if(Player.ammo <= 0){
for(int t = 0; t < 10; t ++){
}
Player.ammo = 3;
}
}
}
It's supposed to wait a bit and then set the ammo to 3, but as soon as the ammo becomes 0, it is set to 3 instantly. What am I doing wrong?
I've tried using sleep, but the entire application would stop.
The problem is that your main program waits for tick() to return something.
Think about it like this; if you have this method
public boolean isOne(int num){
Thread.sleep(1000);
if(num==1){return true;}
return false;
}
and
boolean result = isOne(1);
if(result){ //can't be ran until isOne(1) returns the boolean
//do something
}
You can't continue with you main class when you call isOne() because you dont have the value of the boolean it returns. you have to wait for it to return the value, and then you can continue with the main method
The solution is threading. I'm not an expert on it, so you will need to consult someone else or an online resource, but I think it would look something like this:
public void tick(){
new Thread({ new Runnable(){
#Override
public void run(){
if(Player.ammo <= 0){
Thread.sleep(*seconds* times 1000);
Player.ammo = 3;
}
}).start();
}
There are two problems here.
as soon as the ammo becomes 0, it is set to 3 instantly. What am I doing wrong?
That's because the for loop does nothing. When you enter tick() and Player.ammo is 0, you instantly set it to 3.
I've tried using sleep, but the entire application would stop.
If you only have one thread, that is what Thread.sleep does.
I suspect that what you are attempting is more difficult than you think...
You need a main loop that controls the pace of the game. I might sleep() to ensure that the game does not run too fast.
Each pass, it must instruct every player, or whatever constructs you use, to update themselves. As one of the comments noted, that might involve incrementing a counter to replenish ammo.

Time limited for user input [duplicate]

I'm writing a testing system and i all i want to do is to count how many seconds had user spent on this question. i.e. i print question(standard System.out.println), then wait 5 seconds and if within these 5 seconds user answered(through standard input), i want to keep this value.
If user hasn't provided an answer in 5 seconds, it must skip this question and continue.
The problem is I'm reading user answers via Scanner object, and something like in.nextInt() is uncontrollable, I suppose.
How can I solve this problem? Here is fragment of my code without that functionality, can you give me some hints what to add?
public void start() {
questions.prepareQuestions(numQuestions);
Scanner in=new Scanner(System.in);
boolean playerIsRight=false,botIsRight=false;
int playerScore=0,botScore=0;
for (int i = 0; i < numQuestions; i++) {
questions.askQuestion(i);
System.out.print("Your answer(number): ");
playerIsRight=questions.checkAnswer(i,in.nextInt()-1); //in.nextInt() contains the answer
botIsRight=botAnswersCorrectly(i + 1);
if(playerIsRight){ playerScore++; System.out.println("Correct!");}
else System.out.println("Incorrect!");
if(botIsRight) botScore++;
System.out.print("\n");
}
if(botScore>playerScore) System.out.println("Machine won! Hail to the almighty transistors!");
else if(playerScore>botScore) System.out.println("Human won! Hail to the power of nature!");
else System.out.println("Tie. No one ever wins. No one finally loses.");
}
I would use two threads in this case. The main thread writes questions, waits for answers, and keeps score. A child thread reads standard input and sends the answers to the main thread, perhaps via a BlockingQueue.
The main thread can wait for five seconds for an answer by using the poll() method on the blocking queue:
…
BlockingQueue<Integer> answers = new SynchronousQueue();
Thread t = new ReaderThread(answers);
t.start();
for (int i = 0; i < numQuestions; ++i) {
questions.askQuestion(i);
System.out.print("Your answer (number): ");
Integer answer = answers.poll(5, TimeUnit.SECONDS);
playerIsRight = (answer != null) && questions.checkAnswer(i, answer - 1);
…
}
t.interrupt();
If this call returns null, the main thread knows that the child thread didn't receive any input during that time, and can update the score appropriately and print the next question.
The ReaderThread would look something like this:
class ReaderThread extends Thread {
private final BlockingQueue<Integer> answers;
ReaderThread(BlockingQueue<Integer> answers) {
this.answers = answers;
}
#Override
public void run() {
Scanner in = new Scanner(System.in);
while (!Thread.interrupted())
answers.add(in.nextInt());
}
}
Used on System.in, the Scanner will block until the user presses Enter, so it might happen that the user has entered some text but not yet pressed Enter when the main thread times out and moves on to the next question. The user would have to delete their pending entry and enter a new answer for the new question. I don't know of a clean way around this awkwardness, since there's not a reliable way to interrupt the nextInt() call.

parellel search with communications between threads

Suppose I have an int array, an element num and 4 threads.
I'm giving each thread 1/4 of the array to search for num.
(The search method is given below)
public static boolean contains(int[] array, int minIdx, int maxIdx, int num) { ...}
At my "top level", I can schedule 4 threads to search 4 quarters of the array, but how do I ensure ALL the threads stop searching as soon as one of them finds the element (assuming there is NO duplicate in the array, hence the element can appear at most once).
P.S: You see, suppose my 4th thread found the element at the first iteration, I want the top-level method to return immediately as opposed to wait for other 3 guys to complete.
You need explicit signaling. You might consider the built-in interruption mechanism, or you may roll your own because it's very simple.
One idea: share an AtomicBoolean among all the threads and let each one periodically check it. When a thread finds the answer, it flips the boolean. The best option to achieve periodic checking is a nested loop:
for (int i = start; i < end && !done.get();) {
for (int batchLimit = Math.min(i + BATCH_SIZE, end); i < batchLimit; i++) {
// your logic
}
}
This is the easiest for the JIT compiler to optimize.
The price of checking the value is very low whenever the value didn't change. It will be in the L3 cache. The case when the value did change is irrelevant because at that point you're done.
Use a flag to signal when you found the answer and share it between threads. AtomicBoolean is a good option.
Add the boolean to your loop end conditions for example
for (int i = minIdxs ; i < maxIdxs && found.get() == false; ++i){...}
Also share a CountDownLatch of size 4 and countDown() when you are returning from each thread.
Have your main thread await() and it'll mean all threads gracefully finish before you move on in your main thread.
You can write a class who will act like a controller. this class will know each thread and every thread knows the controller. (its like an observer pattern)
If one thread finds the answer, the thread can tell it to the controller which can inform the other threads to stop.
class ControllerOfAllTheThreads{
ArrayList<TheClassesWhichDoTheSearch> list = new ArrayList<TheClassesWhichDoTheSearch>();
public void tellThemWeFoundHim(){
for (TheClassesWhichDoTheSearch theThreads : list) {
if(theThreads.isAlive() && !theThreads.isInterrupted())
theThreads.interrupt();
}
}
}

How to avoid threads to starve

Suppose I have a hotel with m Rooms.
Guests (Threads) come in and out the whole time.
A Room can have lots of people inside, but only one Room will have people. For example:
Guest A (wants Room 1)
Guest B (wants Room 2)
Guest C (wants Room 1)
A can go to Room 1, once all rooms are empty;
B cannot go to Room 2 yet, given that there is another room with people still inside;
C can go to Room 1, because the Room C wants is the only Room with people inside;
Given that A and C leave Room 1, B should be able to go to Room 2
The last Guest to exit a room should stop every other Guests (avoiding them to come in while he is coming out) until it leaves, so the others can continue
How can I implement this somehow the threads will not starve?
For simplicity, suppose that, once the Guest comes inside a room, it sleeps for some seconds and then get out. Here is my (wrong) implementation:
import java.util.ArrayList;
import java.util.Random;
public class Guest extends Thread {
static Rooms rooms = new Rooms(5);
int id;
Guest(int id) {
this.id = id;
}
public void run() {
rooms.join(this);
nap();
rooms.quit(this);
}
public void nap() {
try {
sleep((new Random().nextInt(4000) + 1000));
} catch (InterruptedException e) {
}
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 20; i++) {
Thread t = new Guest(i);
t.start();
Thread.sleep((long) new Random().nextInt(1500) + 1000);
}
}
}
class Rooms {
Room[] rooms;
int busy;
Rooms(int m) {
busy = -1;
rooms = new Room[m + 1];
for (int i = 0; i < m + 1; i++)
rooms[i] = new Room();
}
void join(Guest h) {
if (busy == -1) {
busy = (new Random().nextInt(rooms.length));
}
rooms[busy].add(h);
System.out.println("Guest " + h.id + " came inside room " + busy + " with " + rooms[busy].size() + " people");
}
void quit(Guest h) {
if (rooms[busy].size() == 1) {
setHandler(busy, h);
} else {
rooms[busy].remove(h);
System.out
.println("Guest " + h.id + " came out of room " + busy + " with " + rooms[busy].size() + " people");
}
}
synchronized void setHandler(int numQuarto, Guest ultimo) {
System.out.println("(Last) Guest " + ultimo.id + " came out of room " + busy + " with "
+ rooms[numQuarto].size() + " people");
rooms[numQuarto].remove(ultimo);
busy = -1;
}
}
class Room extends ArrayList<Guest> {
}
To do this with threads -- which is highly artificial, but I suppose it is an exercise -- you need to learn how to make a Thread wait on a condition, and how to notify one or more Threads that the condition they are waiting for may have been satisfied. Conveniently, every object has methods wait(), notify(), and notifyAll() that serve these purposes.
One important consideration with wait / notify is that you must be careful to wait on and notify the correct object. Generally, that's not the Thread you want to be affected, but rather some shared object that all threads involved rely upon for mutual synchronization. In this particular case, it looks like Guest.rooms would do nicely.
The general idea would be that in Rooms.join(), the current thread tests whether it can immediately take a room. If so, it does, and continues as now. If not, however, it invokes wait() (on the Rooms instance, which at that point is this). Whenever that wait() returns, the thread must again check whether it can immediately take the room it wants; if not, it must wait again.
The other half would be in Rooms.quit(). Whenever a thread running that method is the last one out of the room, it must reset busy to indicate that no room is occupied, and then, importantly, invoke notifyAll() to let all threads waiting at that time know that there's a chance to get a room.
You will find that you need to employ proper synchronization for this. In particular, you can invoke wait() and notifyAll() (and notify()) only while holding the monitor of the target object (it will be released for the duration of the wait, and reacquired before wait() returns). You will also need to ensure that you properly synchronize all manipulation of shared objects, however, in this case mainly the Rooms and its members, without preventing threads from proceeding when otherwise they could. In particular, be aware that threads that sleep() do not for that reason release any monitors they may hold.
The rest is up to you. I've given you rather a lot more of a hint than maybe I should, but it truly is a bit tricky to learn how to use wait / notify properly.
You can't. Based on what you've given, other mechanisms would need to be implemented which guarantee no starvation can occur. For example,
Guests (Threads) come in and out the whole time.
So, it's possible that n threads come in for Room m possibly the whole time. It's possible, too, that during that time more threads come in wanting another room. However, they cannot access the room until Room m is first emptied (which may never actually happen). This can continue for any number of rooms and threads. This is the case even if...
For simplicity, suppose that, once the Guest comes inside a room, it
sleeps for some seconds and then get out.
And that's because...
C can go to Room 1, because the Room C wants is the only Room with
people inside;
Which implies that another thread may enter an already occupied room with one or more threads with t time left to sleep. The new thread goes to sleep and won't wake up until after the previous one. While sleeping n more threads may enter the room potentially causing other threads waiting for other rooms to starve.

Categories