0

I have 200 students waiting to enter a room with 200 seats (25 rows and 8 columns). The door capacity is 4 people. When a student enter the room, he chooses random seat (row and column). If the chosen seat is at 9th row or less it takes 1 second to sit, on 18th and less it takes 2 seconds, and if its from 18 to 25 it takes 3 seconds. When any of them take a seat another person must come in the room. The problem is that when the first 4 people enter the room they take seat one by one and not at once. How can I fix that? For example if 2 people choose a seat at 5th row they both need to sit for 1 seconds and two new students must enter the room.

public class Student 
{
int row;
int column;
volatile static int mutex;

//Generating random numbers for row and column
public Student(Seats[][] seats) 
{

    this.row = (int) Math.ceil(Math.random() * 25);
    this.column = (int) Math.ceil(Math.random() * 8);

    if (!seats[row][column].isTaken) 
    {
        seats[row][column].isTaken = true;
    } else 
    {
        do 
        {
            this.row = (int) Math.ceil(Math.random() * 25);
            this.column = (int) Math.ceil(Math.random() * 8);
        } while (!seats[row][column].isTaken);
        seats[row][column].isTaken = true;
    }
}

/*Check if the mutex is 4 (4 people are in the room) then wait
if someone enter the room increment mutex*/
synchronized void add() throws InterruptedException 
{
    while (mutex > 4)
        wait();
    Student.mutex++;

    notifyAll();
}

/* Check if mutex is 0 (no one is in the room) then wait
if the student has sit - decrement mutex and notify*/
synchronized void takeSeat() throws InterruptedException 
{
    while (mutex == 0)
        wait();
    Student.mutex--;
    notifyAll();

}
}

class Seats 
{
int seat;
boolean isTaken;

public Seats(int seat) 
{
    this.seat = seat;
    this.isTaken = false;
}
}


class StudentThread extends Thread 
{

Seats[][] seats = new Seats[25][8];

StudentThread(Seats[][] seats) 
{
    this.seats = seats;
}

public void run() 
{

    try 
    {
        Student student = new Student(seats);
        synchronized (seats) 
        {
            System.out.println("Student enter the room");

            /*call the synchronized method from student 
             that increment the mutex*/
            student.add();

            if (Student.mutex == 4) 
            {
                if (student.row <= 9) 
                {
                    sleep(1000);

                    student.takeSeat();

                    System.out.println("Student take a seat at "
                            + student.row + " " + student.column);
                }
                if (student.row <= 18 && student.row > 9) 
                {
                    sleep(2000);

                    student.takeSeat();

                    System.out.println("Student take a seat at "
                            + student.row + " " + student.column);
                }
                if (student.row <= 25 && student.row > 18) 
                {
                    sleep(3000);

                    student.takeSeat();

                    System.out.println("Student take a seat at "
                            + student.row + " " + student.column);
                }
            }
        }
    } catch (InterruptedException e) 
    {
        e.printStackTrace();
    }
}
}

class Main 
{

public static void main(String[] args) 
{

    Seats[][] seats = new Seats[25][8];

    //Initializing the seats
    for (int i = 0; i < 25; i++)
        for (int j = 0; j < 8; j++) 
        {
            seats[i][j] = new Seats(i);
        }

    for (int i = 0; i < 200; i++) 
    {
        StudentThread T1 = new StudentThread(seats);
        T1.start();
    }
}
}
3
  • What is your question? For threading and processes see oracle docs Commented Dec 6, 2014 at 9:44
  • Your synchronised section of code on seat in StudentThread.run is too long, you should rethink that part. Commented Dec 6, 2014 at 9:55
  • What do you mean by too long? Commented Dec 6, 2014 at 9:58

1 Answer 1

1

Use a Semaphore, they are very practical for these kind of things.

To make the example a bit more realistic: imagine you need to do 200 HTTP get-requests, but the server will ban you if you run more than 4 requests at the same time. The example below shows how you can limit the number of requests running at the same time using a Semaphore.

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class ResourceUsageLimiter {

    static ExecutorService executor = Executors.newCachedThreadPool();
    static int requests = 20;
    static int maxRequestsConcurrent = 4; 
    static int maxRequestTime = 1000;
    static Random randomizer = new Random();
    static Semaphore openSlots = new Semaphore(maxRequestsConcurrent);
    static long startTime = System.currentTimeMillis();

    public static void main(String[] args) {

        try {
            for (int i = 0; i < requests; i++) {
                openSlots.acquire();
                executor.execute(new RequestRunner(i));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            executor.shutdown();
        }
    }

    static long time() {
        return System.currentTimeMillis() - startTime;
    }

    static class RequestRunner implements Runnable {

        int sleepTime, reqId;

        public RequestRunner(int reqId) {
            this.reqId = reqId;
            sleepTime = randomizer.nextInt(maxRequestTime);
        }

        @Override
        public void run() {

            try {
                System.out.println(time() + " " + reqId + " sleeping " + sleepTime);
                Thread.sleep(sleepTime);
                System.out.println(time() + " " + reqId + " sleep done");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                openSlots.release();
            }
        }

    }

}

Ofcourse, another way to limit the maximum number of requests running at the same time in the example is to use a thread pool with a fixed size of 4.

Sign up to request clarification or add additional context in comments.

4 Comments

Is there a way to run fixed number of threads without using Executor?
@user3476022 I'm not sure I understand that question. You can always do new Thread(Runnable).start()?
When I have 200 threads for example, is it possible only 4 of them to run concurrently and when some of those 4 threads is finished, new one from the 196 left starts running? Is it possible to be done without using Executor-like classes?
@user3476022 No, that's the wrong approach to take. Separate the objects to run from the threads that execute them. You feed the threads the objects to run via an Executor-like class. That makes the problem you describe disappear.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.