-1

so I have been working on some Java Multithreading projects to better understand the matter. I wrote some code to solve a car park problem. Basically multiple cars in the form of threads are supposed to randomly enter and exit a set number of parking slots. I guess I haven't quite gotten behind the concept of Java synchronization yet.

Here is my code:

public class CarPark
{
 
    private int slots;

    public CarPark(int slots) 
    { 
        if(slots < 0)
            slots = 0;
        this.slots = slots; 
    } 

    // Try to enter the car park
    public void tryParking(String car)
    {
        
        if (slots >= 1) // At least one free slot to park in the car park
        {
            park(car);  
        }
        else if (slots <= 0) // If there is no free slot then the car has to wait
        {
            System.out.println(car + ": is waiting for a slot. Free slots: " + slots);
        }

    }
    
    // Parking in the car park
    private void park(String car)
    { 
        slots--;
        System.out.println(car + ": is parking. Free slots: " + slots);
    } 

    // Leaving the car park
    public void leave(String car) 
    { 
        slots++;
        System.out.println(car + ": is leaving the car park. Free slots: " + slots);
    }

    public static void main( String[] args)
    {
        // 5 slots
        CarPark carpark = new CarPark(5);

        // 20 Cars
        for (int i=1; i<=20; i++) {
            Car a = new Car("Car " + i, carpark);
        }
    }
}


class Car extends Thread 
{ 
    private CarPark carpark; 

    public Car(String name, CarPark carpark) 
    { 
        super(name); 
        this.carpark = carpark;
        start(); 
    } 

    public void run() 
    {
        try {
            sleep((int)(Math.random() * 1000)); 
        } catch( InterruptedException e) { }
        
        carpark.tryParking(getName()); 
        
        try {
            sleep((int)(Math.random() * 2000)); 
        }
        catch( InterruptedException e) { } 
        
        carpark.leave(getName());
    } 
}

So now I am faced with the problem that cars are exiting the slots (and "produce" free slots) that never parked there in the first place. How do I get the cars to only exit if they parked in the car park first?

starball
  • 20,030
  • 7
  • 43
  • 238
  • your car never waits if there are no free spaces and just goes directly to the next method witch is sleep then leave witch creates the free slots – Anon Dec 20 '22 at 22:17
  • I would bet that you’re expected to use the wait and notify methods in this exercise https://stackoverflow.com/a/2537117/29470 – Tim Moore Dec 20 '22 at 22:33

1 Answers1

0

So now I am faced with the problem that cars are exiting the slots (and "produce" free slots) that never parked there in the first place. How do I get the cars to only exit if they parked in the car park first?

There are many ways to do this. You have a Car object. You could record that the car is parked using boolean field. Or you could just return true or false if tryParking() was able to park the car.

That answers your specific question but really there is no synchronization in your code as written. You don't get synchronization for free just because you use Thread. You need to be using synchronized, volatile, or other locking or thread safe classes if you actually want to synchronize data and protect critical code sections.

Here are some specific problems with your code:

  • You need some synchronization here. When the threads are running in different CPUs, they are all reading the updating the Carpark.slots field. This is the definition of a race condition. Two threads could update the slots from 0 to 1 at the same time leaving the value as 1 instead of 2. I would make this an AtomicInteger instead.
  • As pointed out in the comments, the tryParking() isn't waiting for a space. If you need to wait then you will need to use a synchronized (this) and then this.wait() and this.notify() calls. Getting this correct is non trivial but there are many tutorials on the subject.
  • Threads should never start() themselves in the constructor because of constructor reordering and having the this "escape" to another thread. The caller should call car.start() after the Car constructor returns. See this explanation.
  • It is a better pattern to implement Runnable instead of extending Thread and do a new Thread(new Car()) type model.
  • Be careful about absorbing InterruptedException. Calling Thread.currentThread().interrupt() is a better pattern to make sure you propagate the interrupt status.
Gray
  • 115,027
  • 24
  • 293
  • 354