1

我是 Java 新手,并试图了解同步的工作原理。所以我创建了一个飞机预订系统,我能够模拟多个用户尝试进行预订并使用同步来获得正确的输出。

现在它起作用了,我在想它在现实世界中是如何起作用的。例如,假设应用程序是基于 Swing 构建的,这是一个多用户应用程序。为简单起见,我们假设只有两个平面“AAA”和“BBB”。该应用程序可以安装在每个售票柜台代理的计算机、机场的售货亭以及不同旅行社的计算机中,并且它们都访问相同的数据库。

在这种情况下,每个用户/计算机将有自己的 Reserve 类、Transaction 类和 Plane 类的实例。所以 Transaction 类中只有一个线程/请求,并且没有同步。

我的问题是,如何实际设计/实施像这样的预订系统这样的多用户应用程序,以便所有用户都访问 Transacion 类的一个实例,以便发生同步。您也可以将这个问题视为,我如何构建一个由不同玩家在不同计算机上玩的多用户游戏。另一个例子是当应用程序在 ATM 和柜员机上运行时进行存款、取款和转账的银行系统。

///////////////////////////

Reserve.java ---> 用户提出的每个请求的入口点

/////////////////////////

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 ---> 实际事务发生在这里

/////////////////////////

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 ---> 飞机信息

/////////////////////////

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 ---> 为了模拟用户每次发出请求,从公共数据源/数据库中检索“可用座位数”。/////////////////////////

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;
 }
}
4

2 回答 2

2

简单地说,您将使用所有Transactions 方法synchronized:这将使您相互排斥。

然而,实际上,没有系统是这样设计的。服务器端应用程序没有建模为单个同步对象。相反,持久状态在支持 ACID 事务(原子、并发、隔离和持久)的关系数据库中维护,对象的等价Transaction物是不需要 Java 级别同步的无状态单例对象。这样的对象将被称为服务 bean. 它通常会在依赖注入容器(例如 Spring)中创建,并且会连接到一堆其他对象,例如 DAO(数据访问对象),这反过来又会实现与数据库。依赖注入容器可以很容易地以声明方式构建互连对象的复杂图。一个典型的企业应用程序,例如航空公司的预订系统,包含至少数十个服务 bean 甚至更多的 DAO,它们连接到各种后端系统。

于 2012-12-02T19:05:39.713 回答
2

任何一个

a) 您依靠数据库中的存储过程(确保原子性)来执行操作。

b)您只有一个包含关键部分的实例(服务器)。客户端向它执行请求,服务器告诉是否有可用的座位(操作成功)或没有(操作失败)。

现实世界的操作将主要是 b,它可以使用 a。

于 2012-12-02T19:01:46.473 回答