【发布时间】:2021-01-11 17:12:11
【问题描述】:
我希望能够更改 runTrain() 方法以允许同步以避免两列火车同时通过。
秘鲁公共类扩展铁路{
public Peru() throws SetUpError {
super("Peru",new Delay(0.1,0.3));
}
/**
* Run the train on the railway.
* This method currently does not provide any synchronisation to avoid two
* trains being in the pass at the same time.
*/
public void runTrain() throws RailwaySystemError {
Clock clock = getRailwaySystem().getClock();
Railway nextRailway = getRailwaySystem().getNextRailway(this);
while (!clock.timeOut()) {
choochoo();
getBasket().putStone(this);
while (nextRailway.getBasket().hasStone(this)) {
getBasket().takeStone(this);
siesta();
getBasket().putStone(this);
}
crossPass();
getBasket().takeStone(this);
}
}
}
目前的问题是我当前的方法不允许同步让两列火车同时通过。这两列火车是秘鲁和玻利维亚。
玻利维亚公共类扩展铁路{
public Bolivia() throws SetUpError {
super("Bolivia",new Delay(0.1,0.3));
}
/**
* Run the train on the railway.
* This method currently does not provide any synchronisation to avoid two
* trains being in the pass at the same time.
*/
public void runTrain() throws RailwaySystemError {
Clock clock = getRailwaySystem().getClock();
Railway nextRailway = getRailwaySystem().getNextRailway(this);
while (!clock.timeOut()) {
choochoo();
getBasket().putStone(this);
while (nextRailway.getBasket().hasStone(this)) {
getBasket().takeStone(this);
siesta();
getBasket().putStone(this);
}
crossPass();
getBasket().takeStone(this);
}
}
}
下面是抽象类,所有方法都是从扩展线程中定义的。
公共抽象类铁路扩展线程{ 私有字符串名称; // 铁路名称 私有静态篮子 sharedBasket = new Basket("共享篮子"); // 一个共享 //通知篮 私人篮筐; // 私人篮子 私人铁路系统铁路系统; //这条铁路构成系统的一部分 私人延迟延迟; // 这条铁路使用的延迟
private Position position; // the position of the train on this railway
public Railway(String name,Delay delay) {
this.name = name;
this.delay = delay;
position = Position.END_PASS; // all trains start just after the
basket = new Basket(name + "'s basket");
}
/**
* Register this railway with a railway system
* @param railwaySystem the railway system this railway must be registered with
*/
public void register(RailwaySystem railwaySystem) {
this.railwaySystem = railwaySystem;
}
/**
* Get the railway system this railway is registered with
* @return the railway system this railway is registered with
* @throws ProgrammingError if the railway is not registered
*/
public RailwaySystem getRailwaySystem() throws ProgrammingError {
if (railwaySystem == null) {
throw new ProgrammingError(name + " is not registered with a railway
system");
}
return railwaySystem;
}
/**
* Get this railway's name
* @return this railway's name
*/
public String name() {
return name;
}
/**
* Get this railway's private basket.
* @return this railway's private basket
*/
public Basket getBasket() {
return basket;
}
/**
* Get the shared basket.
* @return the basket shared between all railways.
*/
public static Basket getSharedBasket() {
return sharedBasket;
}
/**
* Use delay to generate a delay for this railway
*/
public void delay() {
delay.delay();
}
// Fields keeping track of trains in the pass
private static int trainsInPass = 0; // how many trains are in the pass
/**
* Defines parts of the railway system. These are specified as:
* <ul>
* <li> START_PASS: just before entering the shared pass.</li>
* <li> IN_PASS: in the shared pass.</li>
* <li> END_PASS: at the end of the shared pass.</li>
* </ul>
* Trains start at the end of the pass, and must thereafter cycle through
* positions START_PASS, IN_PASS, END_PASS.
*/
public static enum Position {
START_PASS, IN_PASS, END_PASS;
public String toString() {
switch (this) {
case START_PASS: return "at the start of the pass";
case IN_PASS: return "in the pass";
case END_PASS: return "at the end of the pass";
default: return "at an undefined position on the railway (ERROR)";
}
}
}
/**
* Enter the pass.
* This method does <i>not</i> check if it is safe to enter the pass. It is
* merely for
* administration of the information about trains in the pass.
* @throws ProgrammingError if this railway thinks it already has a train in
* the pass.
*/
private synchronized void enterPass() throws ProgrammingError {
railwaySystem.trace(name + ": entering pass");
if (position != Position.START_PASS) {
throw new ProgrammingError(name + " cannot enter the pass, it is not "
+ Position.START_PASS + ", it is " + position + ".");
}
position = Position.IN_PASS;
trainsInPass++;
}
/**
* Leave the pass.
* This method is merely for administration of the information about trains in
* the pass.
* @throws ProgrammingError if this railway thinks it does not have a train in
* the pass,
* or if there is no record of any trains in the pass.
*/
private synchronized void leavePass() throws ProgrammingError {
if (position != Position.IN_PASS) {
throw new ProgrammingError(name + " cannot leave the pass, it is not "
+ Position.IN_PASS + ", it is " + position + ".");
}
if (trainsInPass == 0) {
throw new ProgrammingError("There is no train to leave the pass (even
though " + name + " thinks it is in the pass.");
}
position = Position.END_PASS;
trainsInPass--;
railwaySystem.trace(name + ": leaving pass");
}
/**
* Travel round the safe part of the railway (outside the pass).
* @throws ProgrammingError if the train is not currently at the end of the
* pass (and therefore at the start of the
* safe part of the railway).
*/
public void choochoo() throws ProgrammingError {
if (position != Position.END_PASS) {
throw new ProgrammingError(name + " cannot traverse safe section, it is
not " + Position.END_PASS + ", it is " + position + ".");
}
railwaySystem.trace (name + ": choo-choo");
delay();
position = Position.START_PASS;
}
/**
* Have a siesta.
*/
public void siesta() {
railwaySystem.trace(name + ": zzzzz");
delay();
}
/**
* Cross the pass.
* @throws SafetyViolationError if there is/are already train(s) on the pass.
*/
public void crossPass() throws RailwaySystemError {
enterPass();
if (trainsInPass > 1) {
throw new SafetyViolationError("There are now " + trainsInPass + "
trains in the pass!");
}
railwaySystem.trace(name + ": crossing pass");
delay();
leavePass();
}
// Error flag must be shared so that we can stop all railways if something goes
// wrong
private static boolean errorFlag = false;
protected static String errorMessage = "";
/**
* Run the railway.
*/
public void run() {
setErrorFlag(false);
try {
runTrain();
} catch (RailwaySystemError error) {
setErrorFlag(true);
errorMessage = error.getMessage();
System.out.println("!!! Something went wrong with the railway.\n\t" +
errorMessage);
}
if (errorOccurred()) {
System.out.println("!!! " + name() + " shut down because of an
error.\n\t" + errorMessage);
} else {
System.out.println(name() + " shut down because time limit was
reached.");
}
}
/**
* Each railway should independently define how the trains are to be run, using
* the basket(s).
* to maintain safety on the pass.
* @throws RailwaySystemError if a safety violation occurs while the railway is
* being run.
*/
public abstract void runTrain() throws RailwaySystemError, RailwaySystemError;
/**
* Set the shared error flag (if an error occurs).
* @param errorFlag is true iff an error has occured.
*/
public static void setErrorFlag(boolean errorFlag) {
Railway.errorFlag = errorFlag;
}
/**
* Check the current error status.
* @return true iff an error is currently active.
*/
public static boolean errorOccurred() {
return errorFlag;
}
}
我终于得到了包含 main 方法的类。
公共类铁路系统{
private Clock clock = null; // the clock used to time railways - must be initialised for
// each run
private List<Railway> railways;
public RailwaySystem(List<Railway> railways,Clock clock) {
this.clock = clock;
this.railways = railways;
clock.register(this);
for (Railway railway: railways) {
railway.register(this);
}
}
/**
* Start the railway system
*/
private void start() {
clock.start();
for (Railway railway: railways) {
railway.start();
}
}
/**
* Wait for the system to stop
*/
private void stop() throws RailwaySystemError {
try {
clock.join();
for (Railway railway: railways) {
railway.join();
}
} catch (InterruptedException interrupt) {
throw new RailwaySystemError("The railway system was interrupted: " +
interrupt.getMessage());
}
}
/**
* Given a railway, get the next one in the system's list
* @param railway the given railway
* @return the next railway in the list
* @throws ProgrammingError if railway is neither peru not bolivia
*/
public Railway getNextRailway(Railway railway) throws ProgrammingError {
int index = railways.indexOf(railway);
if (index == -1) { // railway is not in the list
throw new ProgrammingError(railway.name() + " is not registered with this system");
}
return railways.get((index+1) % railways.size());
}
/**
* Get this system's clock
* @return the system's clock
* @throws SetUpError if the clock is not initialised
*/
public Clock getClock() throws SetUpError {
if (clock == null) {
throw new SetUpError("Clock has not been intialised");
}
return clock;
}
/**
* Provide a facility for switching tracing on/off.
**/
private boolean tracingOn = false;
/**
* Switch tracing on.
**/
public void traceOn() {
tracingOn = true;
}
/**
* Switch tracing off.
**/
public void traceOff() {
tracingOn = false;
}
/**
* Trace, if tracing is on
* @param trace the trace to be output
*/
public synchronized void trace(String trace) {
if (tracingOn) {
System.out.println(trace);
}
}
public static void main(String[] args) throws RailwaySystemError {
List<Railway> railways = new ArrayList<Railway>();
railways.add(new Peru());
railways.add(new Bolivia());
Clock clock = new Clock(1.0,20); // 20 ticks of 1 second
RailwaySystem system = new RailwaySystem(railways,clock);
system.traceOn();
system.start();
system.stop();
}
}
我需要在我的 runTrain() 方法中允许同步,这是我目前遇到的问题。非常感谢
【问题讨论】:
标签: java synchronization