public static void findThreaded(
			final int threadCount,
			final List<File> files,
			final String targetString,
			final StringMatchVisitor visitor) {
		
		// create finder
		final StringFinder scanner = new StringFinder(targetString);
		
		// create thread pool
		final ThreadPoolExecutor executor = new ThreadPoolExecutor(threadCount, threadCount, 200, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
		
		// find
		for (final File file : files) {
			executor.submit(new Runnable() {
				public void run() {
					try {
						final String str = IOUtils.readEntireFile(file);
						final StringMatcher sm = scanner.matcher(str);
						LineNumberIndex index = null;

						// find matching strings
						while (sm.find()) {
							if (index == null) index = new LineNumberIndex(str);
							final int off = sm.getStart();
							final int lineOffset = index.getLineNumber(off);
							final String line = index.getLine(off);
							final StringMatch match = new StringMatch(file, line, lineOffset, off);
							visitor.found(match);
						}
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			});
		}
		
		try {
			executor.shutdown();
			executor.awaitTermination(10*60, TimeUnit.SECONDS);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}