
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class StringList {
  static final class Entry {
    final String element;
    Entry next;

    Entry(String element) {
      this.element = element;
    }
  }

  private final Entry head;
  // private Entry tail;

  public StringList() {
    /* tail = */ head = new Entry(null); // fake first entry
  }

  public void addLast(String element) {
    Entry entry = new Entry(element);
    Entry last = head;
    for (;;) {
      Entry next = last.next;
      if (next == null) {
        last.next = entry;
        return;
      }
      last = next;
    }
  }

  public int size() {
    int count = 0;
    for (Entry e = head.next; e != null; e = e.next) {
      count++;
    }
    return count;
  }

  private Runnable runnable(int id) {
    return () -> {
      for (int j = 0; j < 1_000; j++) {
        addLast(id + " " + j);
      }
    };
  }

  public static void main(String[] args) throws InterruptedException, ExecutionException {
    int threadCount = 5;
    StringList list = new StringList();
    List<Callable<Object>> tasks = IntStream.range(0, threadCount)
        .mapToObj(list::runnable)
        .map(Executors::callable)
        .collect(Collectors.toList());
    ExecutorService executor = Executors.newFixedThreadPool(threadCount);
    List<Future<Object>> futures = executor.invokeAll(tasks);
    for(Future<Object> future: futures) {
      future.get();
    }
    executor.shutdown();
    System.out.println(list.size());
  }
}