Even a single CPU can do "multiple things at the same time" in a loose sense, but they are not truly in parallel. You can start 100 threads to run on a single core and they will get time slices during which each of them can run a few instructions, thus creating the impression that they are all executing at the same time.
As I've said in another SO post: multithreading on dual core machine?
The term threads usually covers three abstraction layers:
- User threads are threads launched by applications and are mapped N:M to:
- Kernel threads, which are threads managed by the operating system, mapped N:M to:
- Hardware threads, which are the actual physical resources available.
Java threads are user threads. The 4 cores in your CPU count as hardware threads. Since the mapping is N:M across the layers, you can see that you can have several user threads mapped to a smaller number of hardware threads.
Now, having said this, there are generally two classes of thread activities, each with their own quirks:
- I/O threads: these threads spend most of their time waiting on read/write operations from a stream and are blocked in the meantime (they are not scheduled for execution until an event occurs to wake them up). There are light on the CPU and a lot of them can run concurrently even on a single core.
- Computational threads: these thread do a lot of number crunching and use the CPU to the maximum. Generally starting more than (2x the number of available cores) such threads is going to degrade performance, because the CPU has a limited number of functional units: ALUs, FPUs, etc.
The second class of threads above lets you really see the benefit or running a multithreaded java program on your quad-core CPU. Here is a simple example of a program that executes squaring of 1.000.000.000 numbers first sequentially and then in parallel using a thread pool with 4 threads:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
class ThreadTask implements Runnable {
private int total = 0;
public ThreadTask(int total) {
this.total = total;
}
@Override
public void run() {
int value = 0;
for(int i = 0; i < total; i++) {
value = i * i;
}
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
int total = 1000000000;
long start = System.currentTimeMillis();
long value = 0;
for(int i = 0; i < total; i++) {
value = i * i;
}
long stop = System.currentTimeMillis();
System.out.println((stop - start) + " ms");
ExecutorService exec = Executors.newFixedThreadPool(4);
start = System.currentTimeMillis();
for(int i = 0; i < 4; i++) {
exec.submit(new ThreadTask(total / 4));
}
exec.shutdown();
exec.awaitTermination(10, TimeUnit.SECONDS);
stop = System.currentTimeMillis();
System.out.println((stop - start) + " ms");
}
}
Feel free to adjust the value of total
if it's running too fast. Now I'm working on a netbook with Intel Atom, so it not really fast.