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

Posted

技术标签:

【中文标题】Main 方法在执行过程中等待线程完成。为啥?【英文标题】:Main method waits mid-execution for threads to complete. Why?Main 方法在执行过程中等待线程完成。为什么? 【发布时间】:2015-04-20 06:53:10 【问题描述】:

我正在编写一个电梯模拟器,它在单独的线程中运行每个电梯。每部电梯都拥有自己的目的地数组列表。在我的主要方法中,我要求电梯 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

主要方法:

公共类 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);
    

乘客电梯线程

公共乘客电梯(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));
    

【问题讨论】:

请将您找到的解决方案发布为答案,而不是更新您的问题。否则,人们会认为这个问题仍然悬而未决。 【参考方案1】:

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

这里是固定的sn-p代码:@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");
    

【讨论】:

以上是关于Main 方法在执行过程中等待线程完成。为啥?的主要内容,如果未能解决你的问题,请参考以下文章

主线程啥都没做,就会等待子线程结束。这是为啥?

设置主线程等待子线程执行的方法

线程和异步的分别与联系

如何将任务委托给主线程并等待其执行完成?

JAVA多线程中,如何让一个线程去等待N个线程执行完成后,再执行。

C ++如何等待在另一个线程上执行的方法然后主线程完成(VS2010)