To extend the answer of @InverseFalcon, here is an example for the write lock by writing to a node:
@Test
public void testPessimisticLocking() throws InterruptedException {
txn.execute(status -> {
session.query("CREATE (n:Lock {uuid:'test'})", Map.of(), false);
return null;
});
ExecutorService executor = Executors.newFixedThreadPool(2);
Runnable task = () -> {
LOG.debug("Starting task");
txn.execute(status -> {
long time = System.nanoTime();
LOG.debug("Locking node with time={}", time);
session.query("MATCH (n:Lock {uuid:'test'}) SET n.time = {0}", Map.of("0", time), false);
LOG.debug("Query done, waiting some time...");
try {
Thread.sleep(5000);
}
catch (InterruptedException e) {
LOG.warn("Interrupted", e);
}
LOG.debug("Waiting done");
return null;
});
LOG.debug("Finished task");
};
for (int i = 0; i < 2; i++) {
executor.execute(task);
}
executor.shutdown();
executor.awaitTermination(20, TimeUnit.MINUTES);
}
The test creates a node of label "Lock". It starts two tasks in parallel that try to acquire the write lock on the node. Each task is waiting 5sec within the transaction once it has acquired the lock (simulates workload). Debug output is:
2019-10-26 09:47:09,502 [pool-3-thread-1] DEBUG - Starting task
2019-10-26 09:47:09,508 [pool-3-thread-1] DEBUG - Locking node with time=82297334790500
2019-10-26 09:47:09,513 [pool-3-thread-2] DEBUG - Starting task
2019-10-26 09:47:09,515 [pool-3-thread-2] DEBUG - Locking node with time=82297342219000
2019-10-26 09:47:09,605 [pool-3-thread-2] DEBUG - Query done, waiting some time...
2019-10-26 09:47:14,627 [pool-3-thread-2] DEBUG - Waiting done
2019-10-26 09:47:14,643 [pool-3-thread-1] DEBUG - Query done, waiting some time...
2019-10-26 09:47:14,645 [pool-3-thread-2] DEBUG - Finished task
2019-10-26 09:47:19,643 [pool-3-thread-1] DEBUG - Waiting done
2019-10-26 09:47:19,841 [pool-3-thread-1] DEBUG - Finished task
In the log you can see that one task is acquiring the lock just when the other task finished the transaction.