The cores are what do the actual work. A thread is like a conveyor belt feeding instructions to the core to tell it what work to do.
As an analogy:
Each core is a human worker at a factory. He picks up a piece of paper (instruction) from a conveyor belt (the thread) to perform a task. If there are gaps between one paper and the next, he sits there doing nothing. This is a single core, with a single thread.
If he instead had 2 conveyor belts feeding him papers, if one is empty, he can pick up an instruction from the other. The worker is able to do more work because he has less idle time. This is 1 core with 2 threads. While this is better than a single conveyor belt, the worker still must perform the work himself, so he's the bottleneck.
But if he's joined by another human worker (adding another core) they can get twice as much work done. The new worker will always have their own conveyor belt (every core has at least 1 thread feeding it).
From least to best performance:
- 1 core, no hyperthreading (1 thread in total)
- 1 core, with hyperthreading (2 threads in total)
- 2 cores, no hyperthreading (2 threads in total)
- 2 cores, with hyperthreading (4 threads in total)
Note how 1 core with hyperthreading has the same # of threads as a regular dual-core, but the dual-core can get more work done.