Hi I am doing a project and I have reached a part where I am very stuck. I have tried to search for ways to learn how to write the while loop for a busy wait but I haven't found anything and my code just runs as an infinite loop. Can someone help explain to me how a busy waiting loop should work and help me break out of this infinite loop?
The project wants the following to happen: In the morning, after the student wakes up (it will take a random time) he will head to the bathroom to get ready for a new school day. If the bathroom is already taken, the student takes a break (use yield()) and later on he will wait (use busy waiting) for the bathroom to become available. Students will use the bathroom in a First Come First Serve basis (you can use a Boolean array/vector for having them released in order).
public class Student implements Runnable
{
private Random rn = new Random();
private String threadNum;
private volatile boolean bathroomFull = false;
private static long time = System.currentTimeMillis();
private Thread t;
public Student(String studentID)
{
threadNum = studentID;
t = new Thread(this, "Student Thread #"+threadNum);
System.out.println("thread created = " + t);
// this will call run() function
t.start();
}
public void run()
{
int waitTime = rn.nextInt(4000 - 2000 + 1)+2000;
System.out.println( "the current time is " + (System.currentTimeMillis() - time) + "and the wait time is: " +waitTime );
//Student wakes up after random time
while((System.currentTimeMillis()-time) < waitTime)
{
// System.out.println("the remaining sleep time is " + (System.currentTimeMillis()-time));
;
}
int a = rn.nextInt(4000 - 2000 + 1)+2000;
try
{
//System.out.println("I'm going to sleep for " +a + " milliseconds");
Thread.sleep(a);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
//this is the busy wait loop where is the bathroom is full then a thread will yield until it is available
int l = rn.nextInt(10 - 1)+1;
bathroomFull = true;
while(bathroomFull)
{
for(int j = 0; j < l; j++)
{
System.out.println("i am in the bathroom for " + l + "minutes " + Thread.currentThread());
}
Thread.yield();
bathroomFull = false;
//exitBathroom();
}
bathroomFull = true;
This is my main method which allows the user to specify how many student threads they want. And yes i don't understand how to implement the change of the value so that the busy wait while loop can be broken.
public static void main(String args[])
{
int numberOfStudents;
numberOfStudents = Integer.parseInt(JOptionPane.showInputDialog("How many students are there in the university? "));
// System.out.println("there are " + numberOfStudents);
for(int i = 0; i < numberOfStudents; i++)
{
new Student(String.valueOf(i+1));
}
new Teacher();
}
Here is a working example of a busy wait. It uses an AtomicBoolean to indicate if the bathroom is occupied or not. Atomic operations are executed in one step, this is important to guarantee thread-safety. We could also use a normal boolean and write compareAndSet
ourselves:
private static synchronized boolean compareAndSet(boolean expected, boolean value) {
if (occupied == expected) { // (1)
occupied = value; // (2)
return true;
} else {
return false;
}
}
This is the equivalent (for this example) of the Java implementation. synchronized
is needed otherwise it would be possible that two threads succeed the test at (1)
before (2)
was executed (because those 2 operations aren't atomic) and then two people would go in the bathroom together...
import java.util.concurrent.atomic.AtomicBoolean;
public class Student extends Thread {
// note the static: there is only one bathroom for all students
private static AtomicBoolean occupied = new AtomicBoolean(false);
private String name;
public Student(String name) {
this.name = name;
}
private void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
System.out.println(name + " wet his/her pants");
}
}
@Override
public void run() {
int r = (int)(Math.random() * 5000);
System.out.println(name + " sleeps for " + r + " ms");
sleep(r);
System.out.println(name + " goes to bathroom");
// ***** busy wait *****
while (!occupied.compareAndSet(false, true)) {
System.out.println(name + " takes a break");
Thread.yield();
sleep(1000);
}
// ***** end (in bathroom) *****
System.out.println(name + " is in the bathroom");
sleep(1000);
occupied.set(false);
System.out.println(name + " goes to university");
}
public static void main(String[] args) {
new Student("Bob").start();
new Student("Alice").start();
new Student("Peter").start();
new Student("Marcia").start();
new Student("Desmond").start();
new Student("Sophia").start();
}
}
possible output:
Bob sleeps for 2128 ms
Marcia sleeps for 3357 ms
Alice sleeps for 1289 ms
Peter sleeps for 820 ms
Desmond sleeps for 1878 ms
Sophia sleeps for 2274 ms
Peter goes to bathroom
Peter is in the bathroom
Alice goes to bathroom
Alice takes a break
Peter goes to university
Desmond goes to bathroom
Desmond is in the bathroom
Bob goes to bathroom
Bob takes a break
Sophia goes to bathroom
Sophia takes a break
Alice takes a break
Desmond goes to university
Bob is in the bathroom
Sophia takes a break
Alice takes a break
Marcia goes to bathroom
Marcia takes a break
Bob goes to university
Sophia is in the bathroom
Alice takes a break
Marcia takes a break
Sophia goes to university
Alice is in the bathroom
Marcia takes a break
Alice goes to university
Marcia is in the bathroom
Marcia goes to university