final version with multithreading