A thread is a sequence of program instructions that are executed by the machine.
We call a program multi-threaded when a single execution of the program has more than one thread.
Multi-threading can be simulated on a single-processor machine: The processor switches its attention between the various threads at times that are determined by the system's scheduling policy and, by the program itself. I say "simulated", but as far as the programmer is concerned, there is little difference between the behavior of a properly synchronized, multi-threaded program running on a single-processor system and the same program running on a multi-processor system.
A multi-processor system has more than one CPU (CPUs are also known as "cores"). At any given moment, each CPU potentially could be executing a different thread of the same program. Or, different CPUs could be executing different programs.
Hyperthreading blurs the distinction between a single-processor system and a multi-processor system. Hyper-threaded processors are like conjoined twins: They have some of the attributes of separate processors (e.g., each has its own complete register set), but they share some functional units. Hyperthreading is a hardware-design issue that is invisible at the application level. Think of it as a trick that makes more efficient use of the available silicon.