Main 方法在执行过程中等待线程完成。为什么?

Main method waits mid-execution for threads to complete. Why?

我正在编写一个电梯模拟器,它在单独的线程中运行每部电梯。每部电梯都拥有自己的目的地 ArrayList。在我的主要方法中,我调用 2 号电梯移动到 14 层。当它运行到 14 层时,我告诉它停在 13 层(它在 14 层之前停止)。当它前往 13 和 14 时,我也告诉它前往 15。但是,我发现我的主要方法在请求 14 楼后停止,等待电梯到达 14,然后最终执行楼层请求15.

为什么要这样做?想不通了。

这是我的输出:

00:00:00:000  Creating building...
00:00:00:012  Building created - 16 floors, 4 elevators
00:00:00:014  Elevator 1 going to Floor 11 for UP request [Floor Requests: 11, ][Rider Requests:]
00:00:00:015  Elevator 1 moving from Floor 1 to Floor 2 [Floor Requests: 11, ][Rider Requests:]
00:00:00:520  Elevator 1 moving from Floor 2 to Floor 3 [Floor Requests: 11, ][Rider Requests:]
00:00:01:018  Elevator 2 going to Floor 14 for UP request [Floor Requests: 14, ][Rider Requests:]
00:00:01:020  Elevator 2 moving from Floor 1 to Floor 2 [Floor Requests: 14, ][Rider Requests:]
00:00:01:021  Elevator 1 moving from Floor 3 to Floor 4 [Floor Requests: 11, ][Rider Requests:]
00:00:01:521  Elevator 2 going to Floor 13 for UP request [Floor Requests: 13, 14, ][Rider Requests:]
00:00:01:523  Elevator 1 moving from Floor 4 to Floor 5 [Floor Requests: 11, ][Rider Requests:]
00:00:01:523  Elevator 2 moving from Floor 2 to Floor 3 [Floor Requests: 13, 14, ][Rider Requests:]
00:00:02:025  Elevator 1 moving from Floor 5 to Floor 6 [Floor Requests: 11, ][Rider Requests:]
00:00:02:026  Elevator 2 moving from Floor 3 to Floor 4 [Floor Requests: 13, 14, ][Rider Requests:]
00:00:02:529  Elevator 1 moving from Floor 6 to Floor 7 [Floor Requests: 11, ][Rider Requests:]
00:00:02:530  Elevator 2 moving from Floor 4 to Floor 5 [Floor Requests: 13, 14, ][Rider Requests:]
00:00:03:032  Elevator 1 moving from Floor 7 to Floor 8 [Floor Requests: 11, ][Rider Requests:]
00:00:03:032  Elevator 2 moving from Floor 5 to Floor 6 [Floor Requests: 13, 14, ][Rider Requests:]
00:00:03:537  Elevator 1 moving from Floor 8 to Floor 9 [Floor Requests: 11, ][Rider Requests:]
00:00:03:539  Elevator 2 moving from Floor 6 to Floor 7 [Floor Requests: 13, 14, ][Rider Requests:]
00:00:04:040  Elevator 1 moving from Floor 9 to Floor 10 [Floor Requests: 11, ][Rider Requests:]
00:00:04:042  Elevator 2 moving from Floor 7 to Floor 8 [Floor Requests: 13, 14, ][Rider Requests:]
00:00:04:542  Elevator 1 moving from Floor 10 to Floor 11 [Floor Requests: 11, ][Rider Requests:]
00:00:04:544  Elevator 2 moving from Floor 8 to Floor 9 [Floor Requests: 13, 14, ][Rider Requests:]
00:00:05:047  Elevator 2 moving from Floor 9 to Floor 10 [Floor Requests: 13, 14, ][Rider Requests:]
00:00:05:047  Elevator 1 Doors Open
00:00:05:551  Elevator 1 Doors Close
00:00:05:550  Elevator 2 moving from Floor 10 to Floor 11 [Floor Requests: 13, 14, ][Rider Requests:]
00:00:06:054  Elevator 2 moving from Floor 11 to Floor 12 [Floor Requests: 13, 14, ][Rider Requests:]
00:00:06:556  Elevator 2 moving from Floor 12 to Floor 13 [Floor Requests: 13, 14, ][Rider Requests:]
00:00:07:062  Elevator 2 Doors Open
00:00:07:566  Elevator 2 Doors Close
00:00:07:567  Elevator 2 moving from Floor 13 to Floor 14 [Floor Requests: 14, ][Rider Requests:]
00:00:08:069  Elevator 2 Doors Open
00:00:08:570  Elevator 2 Doors Close
00:00:08:571  Let's see when this is being called00:00:08:572  Elevator 2 going to Floor 15 for UP request [Floor Requests: 15, ][Rider Requests:]
00:00:08:572  Elevator 2 moving from Floor 14 to Floor 15 [Floor Requests: 15, ][Rider Requests:]
00:00:09:076  Elevator 2 Doors Open
00:00:09:582  Elevator 2 Doors Close

主要方法:

public class ElevatorSimulatorMain {

private static long startTime = System.currentTimeMillis();

public static void main(String[] args) {

    // make a building with elevators
    System.out.println(getTimeStamp() + "Creating building...");
    Building testBuilding = new Building(16, 4); //16 floors and 4 elevators
    System.out.printf(getTimeStamp()
            + "Building created - %d floors, %d elevators\n", 
            testBuilding.getNumFloors(), testBuilding.getNumElevators());

    // create a thread for each elevator
    for (int i = 1; i <= testBuilding.getNumElevators(); i++) {
        Thread t = new Thread(testBuilding.getPassengerElevatorbyID(i));
        t.start();
    }

    // Elevator 1 to floor 11
    try {
        testBuilding.getController().sendElevator(11, 1);
        Thread.sleep(1000);
    } catch (InterruptedException ex) {
        Logger.getLogger(ElevatorSimulatorMain.class.getName()).log(Level.SEVERE, null, ex);
    }

    // Elevator 2 to floor 14
    try {
        testBuilding.getController().sendElevator(14, 2);
        Thread.sleep(500);
    } catch (InterruptedException ex) {
        Logger.getLogger(ElevatorSimulatorMain.class.getName()).log(Level.SEVERE, null, ex);
    }

    // Elevator 2 to floor 13 while still in transit to floor 14
    try {
        testBuilding.getController().sendElevator(13, 2);
    } catch (InterruptedException ex) {
        Logger.getLogger(ElevatorSimulatorMain.class.getName()).log(Level.SEVERE, null, ex);
    }

    System.out.printf(ElevatorSimulatorMain.getTimeStamp() + "Let's see when this is being called");
    // Elevator 2 to floor 15 while still in transit to floor 13
    try {
        testBuilding.getController().sendElevator(15, 2);
    } catch (InterruptedException ex) {
        Logger.getLogger(ElevatorSimulatorMain.class.getName()).log(Level.SEVERE, null, ex);
    }
}

乘客电梯线程

public 乘客电梯(int elevID){

    this.elevID = elevID;
    travelSpeed = 500;  // in milliseconds
    doorSpeed = 500;    // in milliseconds
    currentFloor = 1;
    defaultFloor = 1;
    currentState = Direction.IDLE;
    tempDestinations = new ArrayList<>();
    upDestinations = new ArrayList<>();
    downDestinations = new ArrayList<>();
}

@Override
public void run() {

    boolean running = true; // flag for keeping the thread running

    while (running) {
        try {
            synchronized (tempDestinations) {
                if (upDestinations.isEmpty() && downDestinations.isEmpty()){
                    tempDestinations.wait();
                    if (!downDestinations.isEmpty()) {
                        processDownRequest();
                    }
                    else if (!upDestinations.isEmpty()) {
                        processUpRequest();
                    }
                }
            }
        }
        catch (InterruptedException ex) {
            System.out.println("Interrupted! Going back to check for " +
                    "requests/wait");
        }
    }
}

/**
 * Make elevator go up one floor. Takes travelSpeed time
 * @throws InterruptedException 
 */
@Override
public void moveUp() throws InterruptedException {
    setCurrentFloor(currentFloor++);
    Thread.sleep(travelSpeed);
}

/**
 * Make elevator go down one floor. Takes travelSpeed time
 * @throws InterruptedException 
 */
@Override
public void moveDown() throws InterruptedException{
    setCurrentFloor(currentFloor--);
    Thread.sleep(travelSpeed);
}

/**
 * Make elevator door open for doorSpeed time. When door is open people
 * move into elevator
 * @throws InterruptedException 
 */
@Override
public void openDoors() throws InterruptedException{
    System.out.printf(ElevatorSimulatorMain.getTimeStamp() + "Elevator %d "
            + "Doors Open\n", elevID);
    Thread.sleep(doorSpeed);
    System.out.printf(ElevatorSimulatorMain.getTimeStamp() + "Elevator %d "
            + "Doors Close\n", elevID);
}

/**
 * Moves the elevator up to the first destination in upDestinations.
 * When it gets there, it removes the destination from upDestinations.
 * @throws InterruptedException 
 */
private void processUpRequest() throws InterruptedException {

    while (!upDestinations.isEmpty()) {
        if (currentFloor != upDestinations.get(0)) {
            currentState = Direction.UP;
            System.out.printf(ElevatorSimulatorMain.getTimeStamp() 
                    + "Elevator %d moving from Floor %d to Floor %d "
                    + "[Floor Requests: %s][Rider Requests:]\n", elevID,
                    currentFloor, ++currentFloor, 
                    printRequests(upDestinations));
            moveUp();
        }
        else {
            upDestinations.remove(0);
            openDoors();
        }
    }
    currentState = Direction.IDLE;
}

/**
 * Moves the elevator down to the first destination in downDestinations.
 * When it gets there, it removes the destination from downDestinations.
 * @throws InterruptedException 
 */
private void processDownRequest() throws InterruptedException {

    while (!downDestinations.isEmpty()) {
        if (currentFloor != downDestinations.get(0)) {
            currentState = Direction.DOWN;
            System.out.printf(ElevatorSimulatorMain.getTimeStamp() 
                    + "Elevator %d moving from Floor %d to Floor %d "
                    + "[Floor Requests: %s][Rider Requests:]\n", elevID,
                    currentFloor, --currentFloor, 
                    printRequests(downDestinations));
            moveDown();
        }
        else {
            downDestinations.remove(0);
            openDoors();
        }
    }
    currentState = Direction.IDLE;
}

/**
 * add a destination for the elevator to stop at
 * @param floor for the elevator to travel to
 */
public void addDestination(int floor) {

    // if elevator is moving down
    if (!downDestinations.isEmpty() && currentState == Direction.DOWN) {
        addDestinationWhenMovingDown(floor);
    }

    // if elevator is moving UP  
    else if (!upDestinations.isEmpty() && currentState == Direction.UP) {
        addDestinationWhenMovingUp(floor);
    }

    // if elevator is IDLE
    else {
        addDestinationWhenIdle(floor);
    }

    /* 
    this is just an object to conveniently call on to indicate there must
    have been a destination added since you cannot call wait on 
    upDestinations and downDestinations at the same time.
    */
    synchronized (tempDestinations) {
        tempDestinations.notifyAll();
    }
}

/**
 * Handle adding a destination when the elevator state is idle.
 * @param floor - the floor the request was made on
 */
private void addDestinationWhenIdle(int floor) {

    // request to go UP
    if (floor > currentFloor) {
        upDestinations.add(floor);
        System.out.printf(ElevatorSimulatorMain.getTimeStamp() 
                + "Elevator %d going to Floor %d for UP request"
                + " [Floor Requests: %s][Rider Requests:]\n",elevID, 
                upDestinations.get(0), 
                printRequests(upDestinations));
    }

    // request to go DOWN
    else if (floor < currentFloor) {
            downDestinations.add(floor);
            System.out.printf(ElevatorSimulatorMain.getTimeStamp()
                    + "Elevator %d going to Floor %d for DOWN request"
                    + " [Floor Requests: %s][Rider Requests:]\n",elevID, 
                    downDestinations.get(0), 
                    printRequests(downDestinations));
    }

    // already on that floor, do nothing
    else {}
}

/**
 * Handle adding a destination when the elevator is moving up. Checks to see
 * if request is in the destination list already. If it isn't, it adds it to
 * the list and sorts the list in order of when the elevator should go first
 * @param floor - the floor the request was made on
 */
private void addDestinationWhenMovingUp(int floor) {
    // if it isn't already in the list, add it and sort it.
    // do nothing if it is already in the list
    if (!upDestinations.contains(floor)) {
        upDestinations.add(floor);
        Collections.sort(upDestinations);
        System.out.printf(ElevatorSimulatorMain.getTimeStamp() 
                + "Elevator %d going to Floor %d for UP request"
                + " [Floor Requests: %s][Rider Requests:]\n",elevID, 
                upDestinations.get(0), 
                printRequests(upDestinations));
    }
}

/**
 * Handle adding a destination when the elevator is moving down. Checks to 
 * see if request is in the destination list already. If it isn't, it adds 
 * it to the list and sorts the list in order of when the elevator should go
 * first.
 * @param floor - the floor the request was made on
 */
private void addDestinationWhenMovingDown(int floor) {
    // if it isn't already in the list, add it and sort it.
    // do nothing if it is already in the list
    if (!downDestinations.contains(floor)) {
        downDestinations.add(floor);
        Collections.sort(upDestinations);
        Collections.reverse(upDestinations);
        System.out.printf(ElevatorSimulatorMain.getTimeStamp()
                + "Elevator %d going to Floor %d for DOWN request"
                + " [Floor Requests: %s][Rider Requests:]\n",elevID, 
                downDestinations.get(0), 
                printRequests(downDestinations));
    }
}

已解决:锁定的 tempDestinationsList 在尝试执行电梯移动方法时持有锁。我将锁更改为释放,然后调用了进程请求的方法。

这是固定的代码片段:@Override public void 运行() {

boolean running = true; // flag for keeping the thread running

while (running) {
    try {
        synchronized (tempDestinations) {
            if (upDestinations.isEmpty() && downDestinations.isEmpty()){
                tempDestinations.wait();
            }
        }
        if (!downDestinations.isEmpty()) {
            processDownRequest();
        }
        else if (!upDestinations.isEmpty()) {
            processUpRequest();
        }
    }
    catch (InterruptedException ex) {
        System.out.println("Interrupted! Going back to check for " +
                "requests/wait");
    }
}