Если я правильно понял задачу, то вы в основном хотите «отслеживать» движения телефона и считать это ошибкой, если они не перемещены в правильном порядке. Это означает, что вам придется отслеживать состояние каждого телефона в отдельности , предполагая, что состояние, возвращаемое методом moved()
, может измениться в любой момент времени.
Если это правильно, то одним из подходов будет следующий:
- Определите ожидаемую последовательность телефонов для перемещения (это последовательность, которую они имеют в списке)
- Для каждого телефона запланируйте задачу, которая контролирует состояние телефона
- Если задача обнаруживает, что телефон был перемещен, поместите его в (блокирующую) очередь
- Подождите, пока каждый телефон будет помещен в очередь, и убедитесь, что он отображается там в ожидаемом порядке
Это реализовано здесь, чтобы показать основную идею. Могут быть оговорки, в зависимости от частоты опроса и тому подобное, но я думаю, что это может быть разумным подходом. Альтернативные реализации (например, с использованием ExecutorCompletionService
) могут быть возможны, хотя:
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Queue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
public class PhoneMoveDetector
{
// Dummy phone class that changes its "moved()" state after a certain time
private static class PhoneX1
{
private final String name;
private volatile boolean moved = false;
PhoneX1(String name, long delayMs)
{
this.name = name;
Thread t = new Thread(() ->
{
try
{
Thread.sleep(delayMs);
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
System.out.println("Moving " + this);
moved = true;
});
t.start();
}
boolean moved()
{
return moved;
}
@Override
public String toString()
{
return name;
}
}
public static void main(String[] args)
{
checkRightMoveOrder();
detectWrongMoveOrder();
}
private static void checkRightMoveOrder()
{
List<PhoneX1> phones = new ArrayList<PhoneX1>();
phones.add(new PhoneX1("A", 1500));
phones.add(new PhoneX1("B", 3000));
phones.add(new PhoneX1("C", 4500));
phones.add(new PhoneX1("D", 6000));
MoveDetector moveDetector = new MoveDetector(phones);
System.out.println("Checking right move order");
for (PhoneX1 phone : phones)
{
try
{
moveDetector.waitForExpectedToMove();
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
return;
}
System.out.println("Moved " + phone);
}
}
private static void detectWrongMoveOrder()
{
List<PhoneX1> phones = new ArrayList<PhoneX1>();
phones.add(new PhoneX1("A", 1500));
phones.add(new PhoneX1("B", 3000));
phones.add(new PhoneX1("C", 2000)); // Should be moved later
phones.add(new PhoneX1("D", 6000));
MoveDetector moveDetector = new MoveDetector(phones);
System.out.println("Detecting wrong move order");
for (PhoneX1 phone : phones)
{
try
{
moveDetector.waitForExpectedToMove();
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
return;
}
System.out.println("Moved " + phone);
}
}
private static class MoveDetector
{
private final Queue<PhoneX1> expectedPhones;
private final BlockingQueue<PhoneX1> movedPhones;
MoveDetector(List<PhoneX1> phones)
{
expectedPhones = new LinkedList<PhoneX1>(phones);
movedPhones = new LinkedBlockingDeque<PhoneX1>();
ExecutorService executor = Executors.newCachedThreadPool();
List<Callable<Object>> observers =
new ArrayList<Callable<Object>>();
for (PhoneX1 phone : phones)
{
Runnable r = () ->
{
while (!phone.moved())
{
try
{
Thread.sleep(50);
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
return;
}
}
movedPhones.offer(phone);
};
observers.add(Executors.callable(r));
}
Thread t = new Thread(() ->
{
try
{
executor.invokeAll(observers);
executor.shutdownNow();
}
catch (InterruptedException e1)
{
Thread.currentThread().interrupt();
}
});
t.start();
}
void waitForExpectedToMove() throws InterruptedException
{
PhoneX1 moved = movedPhones.take();
PhoneX1 expected = expectedPhones.peek();
if (!Objects.equals(expected, moved))
{
System.out.println("Moved " + moved + ", but expected "
+ expected + " - ERROR!");
// Handle this case as desired, e.g. by doing a
// throw new IllegalStateException();
}
else
{
System.out.println("Moved " + moved + ", as expected");
expectedPhones.remove();
}
}
}
}
Вывод отображается здесь:
Checking right move order
Moving A
Moved A, as expected
Moved A
Moving B
Moved B, as expected
Moved B
Moving C
Moved C, as expected
Moved C
Moving D
Moved D, as expected
Moved D
Detecting wrong move order
Moving A
Moved A, as expected
Moved A
Moving C
Moved C, but expected B - ERROR!
Moved B
Moving B
Moved B, as expected
Moved C
Moving D
Moved D, but expected C - ERROR!
Moved D