How to do it...

Follow these steps to implement the example:

  1. First, create the application without using any synchronization mechanism. Create a class named ParkingCash with an internal constant and an attribute to store the total amount of money earned by providing this parking service:
          public class ParkingCash { 
private static final int cost=2;
private long cash;

public ParkingCash() {
cash=0;
}
  1. Implement a method named vehiclePay() that will be called when a vehicle (a car or motorcycle) leaves the parking area. It will increase the cash attribute:
        public void vehiclePay() { 
cash+=cost;
}
  1. Finally, implement a method named close() that will write the value of the cash attribute in the console and reinitialize it to zero:
          public void close() { 
System.out.printf("Closing accounting");
long totalAmmount;
totalAmmount=cash;
cash=0;
System.out.printf("The total amount is : %d",
totalAmmount);
}
}
  1. Create a class named ParkingStats with three private attributes and the constructor that will initialize them:
          public class ParkingStats { 
private long numberCars;
private long numberMotorcycles;
private ParkingCash cash;

public ParkingStats(ParkingCash cash) {
numberCars = 0;
numberMotorcycles = 0;
this.cash = cash;
}
  1. Then, implement the methods that will be executed when a car or motorcycle enters or leaves the parking area. When a vehicle leaves the parking area, cash should be incremented:
        public void carComeIn() { 
numberCars++;
}

public void carGoOut() {
numberCars--;
cash.vehiclePay();
}
        public void motoComeIn() { 
numberMotorcycles++;
}

public void motoGoOut() {
numberMotorcycles--;
cash.vehiclePay();
}
  1. Finally, implement two methods to obtain the number of cars and motorcycles in the parking area, respectively.
  2. Create a class named Sensor that will simulate the movement of vehicles in the parking area. It implements the Runnable interface and has a ParkingStats attribute, which will be initialized in the constructor:
        public class Sensor implements Runnable { 

private ParkingStats stats;

public Sensor(ParkingStats stats) {
this.stats = stats;
}
  1. Implement the run() method. In this method, simulate that two cars and a motorcycle arrive in and then leave the parking area. Every sensor will perform this action 10 times:
        @Override 
public void run() {
for (int i = 0; i< 10; i++) {
stats.carComeIn();
stats.carComeIn();
try {
TimeUnit.MILLISECONDS.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
stats.motoComeIn();
try {
TimeUnit.MILLISECONDS.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
 
stats.motoGoOut();
stats.carGoOut();
stats.carGoOut();
}
}
  1. Finally, implement the main method. Create a class named Main with the main() method. It needs ParkingCash and ParkingStats objects to manage parking:
        public class Main { 

public static void main(String[] args) {

ParkingCash cash = new ParkingCash();
ParkingStats stats = new ParkingStats(cash);

System.out.printf("Parking Simulator ");
  1. Then, create the Sensor tasks. Use the availableProcessors() method (that returns the number of available processors to the JVM, which normally is equal to the number of cores in the processor) to calculate the number of sensors our parking area will have. Create the corresponding Thread objects and store them in an array:
        intnumberSensors=2 * Runtime.getRuntime()
.availableProcessors();
Thread threads[]=new Thread[numberSensors];
for (int i = 0; i<numberSensors; i++) {
Sensor sensor=new Sensor(stats);
Thread thread=new Thread(sensor);
thread.start();
threads[i]=thread;
}
  1. Then wait for the finalization of the threads using the join() method:
        for (int i=0; i<numberSensors; i++) { 
try {
threads[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
  1. Finally, write the statistics of Parking:
            System.out.printf("Number of cars: %d
",
stats.getNumberCars());
System.out.printf("Number of motorcycles: %d ",
stats.getNumberMotorcycles());
cash.close();
}
}

In our case, we executed the example in a four-core processor, so we will have eight Sensor tasks. Each task performs 10 iterations, and in each iteration, three vehicles enter the parking area and the same three vehicles go out. Therefore, each Sensor task will simulate 30 vehicles.

If everything goes well, the final stats will show the following:

  • There are no cars in the parking area, which means that all the vehicles that came into the parking area have moved out
  • Eight Sensor tasks were executed, where each task simulated 30 vehicles and each vehicle was charged 2 dollars each; therefore, the total amount of cash earned was 480 dollars

When you execute this example, each time you will obtain different results, and most of them will be incorrect. The following screenshot shows an example:

We had race conditions, and the different shared variables accessed by all the threads gave incorrect results. Let's modify the previous code using the synchronized keyword to solve these problems:

  1. First, add the synchronized keyword to the vehiclePay() method of the ParkingCash class:
        public synchronized void vehiclePay() { 
cash+=cost;
}
  1. Then, add a synchronized block of code using the this keyword to the close() method:
        public void close() { 
System.out.printf("Closing accounting");
long totalAmmount;
synchronized (this) {
totalAmmount=cash;
cash=0;
}
System.out.printf("The total amount is : %d",totalAmmount);
}
  1. Now add two new attributes to the ParkingStats class and initialize them in the constructor of the class:
        private final Object controlCars, controlMotorcycles; 
public ParkingStats (ParkingCash cash) {
numberCars=0;
numberMotorcycles=0;
controlCars=new Object();
controlMotorcycles=new Object();
this.cash=cash;
}
  1. Finally, modify the methods that increment and decrement the number of cars and motorcycles, including the synchronized keyword. The numberCars attribute will be protected by the controlCars object, and the numberMotorcycles attribute will be protected by the controlMotorcycles object. You must also synchronize the getNumberCars() and getNumberMotorcycles() methods with the associated reference object:
        public void carComeIn() { 
synchronized (controlCars) {
numberCars++;
}
}

public void carGoOut() {
synchronized (controlCars) {
numberCars--;
}
cash.vehiclePay();
}
 
public void motoComeIn() {
synchronized (controlMotorcycles) {
numberMotorcycles++;
}
}

public void motoGoOut() {
synchronized (controlMotorcycles) {
numberMotorcycles--;
}
cash.vehiclePay();
}
  1. Execute the example now and see the difference when compared to the previous version.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.27.53