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 方法在执行过程中等待线程完成。为啥?的主要内容,如果未能解决你的问题,请参考以下文章