public boolean addItem(Item item) {
    if (items.size() < inventorySize) {
      lock.lock();
      try {
        if (items.size() < inventorySize) {
          items.add(item);
          var thread = Thread.currentThread();
          LOGGER.info("{}: items.size()={}, inventorySize={}", thread, items.size(), inventorySize);
          return true;
        }
      } finally {
        lock.unlock();
      }
    }
    return false;
  }
@Test
  void testAddItem() {
    assertTimeout(ofMillis(10000), () -> {
      // Create a new inventory with a limit of 1000 items and put some load on the add method
      final var inventory = new Inventory(INVENTORY_SIZE);
      final var executorService = Executors.newFixedThreadPool(THREAD_COUNT);
      IntStream.range(0, THREAD_COUNT).<Runnable>mapToObj(i -> () -> {
        while (inventory.addItem(new Item())) ;
      }).forEach(executorService::execute);

      // Wait until all threads have finished
      executorService.shutdown();
      executorService.awaitTermination(5, TimeUnit.SECONDS);

      // Check the number of items in the inventory. It should not have exceeded the allowed maximum
      final var items = inventory.getItems();
      assertNotNull(items);
      assertEquals(INVENTORY_SIZE, items.size());

      assertEquals(INVENTORY_SIZE, appender.getLogSize());

      // ... and check if the inventory size is increasing continuously
      IntStream.range(0, items.size())
          .mapToObj(i -> appender.log.get(i).getFormattedMessage()
              .contains("items.size()=" + (i + 1)))
          .forEach(Assertions::assertTrue);
    });
  }