@Test
public void testReuseSequentialMultithreading() throws IOException, InterruptedException {
// Create the analyzer
final ComboAnalyzer cb = new ComboAnalyzer(TEST_VERSION_CURRENT, new WhitespaceAnalyzer(TEST_VERSION_CURRENT));
final NamedAnalyzer namedAnalyzer = new NamedAnalyzer("name", AnalyzerScope.INDEX, cb);
// Use N threads, each running M times
Thread[] threads = new Thread[4];
final int runs = 4;
// The lock ensures only one thread is running at a given time
final Lock lock = new ReentrantLock();
// This integer ensures each thread runs with a different input
// Inputs must not be exchanged from one thread to another during object reuse
final AtomicInteger sequence = new AtomicInteger(0);
final AtomicBoolean abort = new AtomicBoolean(false);
// The barrier ensures that each thread gets a chance to execute, for each run
// We must use extra care so that all threads can exit as soon as one fails
final CyclicBarrier latch = new CyclicBarrier(threads.length);
// Code executed on each thread
Runnable code = new Runnable() {
@Override
public void run() {
// Run multiple times before quitting
for (int run = 0 ; run < runs ; ++run) {
try {
// Serialize runs
lock.lock();
// Get unique sequence number
int i = sequence.getAndIncrement();
// Check the analysis went well, including the unique sequence number
assertTokenStreamContents(namedAnalyzer.tokenStream("field", new StringReader("just a little test " + i)),
new String[]{"just", "a", "little", "test", Integer.toString(i)},
new int[]{0, 5, 7, 14, 19},
new int[]{4, 6, 13, 18, 19 + ("" + i).length()},
new int[]{1, 1, 1, 1, 1});
} catch (Exception e) {