I am new to Java and was trying to understand how synchronizatioon works. So I created a Plane Reservation System and I am able to simulate mutliple users trying to make a reservation and use Synchromization to get the correct output.
Now that it works, I am thinking how this works in the real world. For instance, let us say the application is built on Swing and this is a multi user application. For simplicity let us assume there are only two planes ‘AAA’ and ‘BBB’. This application may be installed in each of the ticket counter agent’s computer , the kiosks at the airport and as well as in the computers of different travel agents and all of them accessing the same database.
In this case, each user/computer will have its own instance of Reserve class, Transaction class and Plane class. So there is only one thread/request in the Transaction class and there is no synchronization.
My question is, how will a mutli user application like this Reservation system actually be designed/implemeneted such that all users are accessing one instance of Transacion class so that synchronization can happen. You can also look at this question as, how can I build a mutli-user game played by different players across different computers. One more example would be a Banking system to make deposits, withdrawals and transfers when the application is running in the ATM as well as the Teller’s machine.
///////////////////////////////
Reserve.java —> Point of entry for each request made by a user
/////////////////////////////
import java.io.IOException;
public class Reserve {
static int queryseatsavailableinx;
static int queryseatsavailableiny;
static
{
seats s = null;
try {
s = new seats();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
queryseatsavailableinx = s.getseatsinplanex("AAA");
queryseatsavailableiny = s.getseatsinplanex("BBB");
} catch (IOException e) {
e.printStackTrace();
}
}
static final Plane x1 = new Plane("AAA", 001, queryseatsavailableinx );
static final Plane y1 = new Plane("BBB", 002, queryseatsavailableiny);
static final Transaction trans = new Transaction();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new Runnable() {
public void run() {
trans.getPlaneInfo(x1);
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
//trans.getPlaneInfo(x1);
trans.reserveSeats(x1,3);
}
});
Thread t3 = new Thread(new Runnable() {
public void run() {
//trans.getPlaneInfo(y1);
trans.reserveSeats(y1,8);
}
});
Thread t4 = new Thread(new Runnable() {
public void run() {
//trans.getPlaneInfo(x1);
trans.reserveSeats(x1,2);
}
});
t1.start();
t2.start();
t3.start();
t4.start();
t1.join();
t2.join();
t3.join();
t4.join();
}
}
///////////////////////////////
Transaction.java —> Actual transaction happens here
/////////////////////////////
public class Transaction {
public void getPlaneInfo(Plane x){
synchronized(this){
int number = x.getSeatCapacity();
String planename=x.getPlaneName();
System.out.printf("The number of seats in plane %s is %d\n",planename,number);
}
}
public void reserveSeats(Plane x, int seatstobereserved) {
synchronized(this){
x.updateSeatCapacity(seatstobereserved);
}
}
}
///////////////////////////////
Plane.java —> Information about the plane
/////////////////////////////
final public class Plane {
private String planename = null;
private int planeid = 0;
private int availableseatcapacity = 0;
Plane(String planename, int planeid, int seatcapacity) {
this.planename = planename;
this.planeid = planeid;
this.availableseatcapacity = seatcapacity;
}
public String getPlaneName() {
return planename;
}
public int getPlaneId() {
return planeid;
}
public int getSeatCapacity() {
return availableseatcapacity;
}
public void updateSeatCapacity(int reservedseats) {
availableseatcapacity -= reservedseats;
System.out.printf("\n%d Seats successfully reserved and remaining seats " +
"in the plane %s are %d\n",reservedseats, planename,availableseatcapacity);
}
}
///////////////////////////////
Seats.java —> To simulate each time a request is made by the user the ‘number of availabe seats’ is retrieved from a common datasource/db.
/////////////////////////////
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
final public class seats {
seats() throws IOException {
DataOutputStream di1 = new DataOutputStream(new FileOutputStream(
"\\PlaneReservation\\bin\\a.bin"));
DataOutputStream di2 = new DataOutputStream(new FileOutputStream(
"\\PlaneReservation\\bin\\b.bin"));
di1.writeInt(300);
di2.writeInt(200);
di1.flush();
di2.flush();
di1.close();
di2.close();
}
public int getseatsinplanex(String s) throws IOException {
if (s.equals("AAA")) {
FileInputStream fis1 = new FileInputStream("\\PlaneReservation\\bin\\a.bin");
DataInputStream dis1 = new DataInputStream(fis1);
int number = 0;
boolean eof = false;
while (!eof) {
try {
number = dis1.readInt();
// System.out.println(number);
} catch (EOFException eofx) {
eof = true;
dis1.close();
}
}
return number;
} else if (s.equals("BBB")) {
FileInputStream fis2 = new FileInputStream("\\PlaneReservation\\bin\\b.bin");
DataInputStream dis2 = new DataInputStream(fis2);
int number = 0;
boolean eof = false;
while (!eof) {
try {
number = dis2.readInt();
//System.out.println(number);
} catch (EOFException eofx) {
eof = true;
dis2.close();
}
}
return number;
}
return 0;
}
}
Symplistically, you’d make all
Transactions methodssynchronized: this would give you mutual exclusion.In reality, however, no system is designed like that. The server-side application is not modelled as a single synchronized object. Rather, the durable state is maintained in a relational database that supports ACID transactions (atomic, concurrent, isolated, and durable) and the equivalent of the
Transactionobject is a stateless singleton object that needs no synchronization on Java level. Such an object would be called a service bean. It would typically be created within a Dependency Injection container, such as Spring, and it would be connected to a bunch of other objects, such as DAOs (Data Access Object), which would in turn implement the low-level logic of interaction with a database. The Dependency Injection container makes it easy to declaratively build a complex graph of interconnected objects. A typical enterprise application, such as an airline’s reservation system, contains at least tens of service beans and even more DAOs, which connect to a variety of back-end systems.