Source:
public void testConcurrentGraphChange() throws InterruptedException { final GraphHopperStorage graph = new GraphBuilder(encodingManager).create(); initGraph(graph); graph.edge(1, 2, 10, true); final AtomicInteger checkPointCounter = new AtomicInteger(0); final GraphHopper graphHopper = new GraphHopper() { @Override protected ChangeGraphHelper createChangeGraphHelper(Graph graph, LocationIndex locationIndex) { return new ChangeGraphHelper(graph, locationIndex) { @Override public long applyChanges(EncodingManager em, Collection<JsonFeature> features) { try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } checkPointCounter.incrementAndGet(); return super.applyChanges(em, features); } }; } }.setStoreOnFlush(false).setEncodingManager(encodingManager).setCHEnabled(false). loadGraph(graph); GHResponse rsp = graphHopper.route(new GHRequest(42, 10.4, 42, 10)); assertFalse(rsp.toString(), rsp.hasErrors()); assertEquals(1800, rsp.getBest().getTime()); final List<JsonFeature> list = new ArrayList<>(); Map<String, Object> properties = new HashMap<>(); properties.put("speed", 5); list.add(new JsonFeature("1", "bbox", new BBox(10.399, 10.4, 42.0, 42.001), null, properties)); Thread thread1 = new Thread() { @Override public void run() { graphHopper.changeGraph(list); checkPointCounter.incrementAndGet(); } }; thread1.start(); Thread thread2 = new Thread() { @Override public void run() { assertEquals(0, checkPointCounter.get()); GHResponse rsp = graphHopper.route(new GHRequest(42, 10.4, 42, 10)); assertFalse(rsp.toString(), rsp.hasErrors()); assertEquals(8400, rsp.getBest().getTime()); checkPointCounter.incrementAndGet(); } }; thread2.start(); thread1.join(); thread2.join(); assertEquals(3, checkPointCounter.get()); }

Target:
public void testConcurrentGraphChange() throws InterruptedException { final GraphHopperStorage graph = new GraphBuilder(encodingManager).create(); initGraph(graph); graph.edge(1, 2, 10, true); final CountDownLatch latch = new CountDownLatch(1); final AtomicInteger checkPointCounter = new AtomicInteger(0); final GraphHopper graphHopper = new GraphHopper() { @Override protected ChangeGraphHelper createChangeGraphHelper(Graph graph, LocationIndex locationIndex) { return new ChangeGraphHelper(graph, locationIndex) { @Override public long applyChanges(EncodingManager em, Collection<JsonFeature> features) { latch.countDown(); try { Thread.sleep(400); } catch (InterruptedException e) { throw new RuntimeException(e); } checkPointCounter.incrementAndGet(); return super.applyChanges(em, features); } }; } }.setStoreOnFlush(false).setEncodingManager(encodingManager).setCHEnabled(false). loadGraph(graph); GHResponse rsp = graphHopper.route(new GHRequest(42, 10.4, 42, 10)); assertFalse(rsp.toString(), rsp.hasErrors()); assertEquals(1800, rsp.getBest().getTime()); final List<JsonFeature> list = new ArrayList<>(); Map<String, Object> properties = new HashMap<>(); properties.put("speed", 5); list.add(new JsonFeature("1", "bbox", new BBox(10.399, 10.4, 42.0, 42.001), null, properties)); ExecutorService executorService = Executors.newFixedThreadPool(1); executorService.submit(new Runnable() { @Override public void run() { graphHopper.changeGraph(list); checkPointCounter.incrementAndGet(); } }); latch.await(); assertEquals(0, checkPointCounter.get()); rsp = graphHopper.route(new GHRequest(42, 10.4, 42, 10)); assertFalse(rsp.toString(), rsp.hasErrors()); assertEquals(8400, rsp.getBest().getTime()); executorService.shutdown(); executorService.awaitTermination(3, TimeUnit.SECONDS); assertEquals(2, checkPointCounter.get()); }