Single threads vs multi threads

In software development, understanding how programs handle and execute tasks is very important. Threads are at the core of this, shaping how operations flow within a program.

What are threads?

A thread is the smallest unit of execution within a program.

To more simply put it, think of each thread as a worker under you. A standard program will give you one worker by default, following the tasks laid out in the source code one at a time. If you add more threads, it’s like hiring extra workers, each able to handle separate tasks simultaneously.

What are single-threads?

In a single-threaded program, the application operates with only one worker(thread) to handle all instructions. Since there is only one worker, and since a worker can complete just one task at a time, all tasks are processed in a strict, linear progression. One task must be FULLY completed before the next one can begin.

When should I use single-threading?

  • Orderly tasks
    • Programs that demand sequential execution, such as processing transactions in order or performing calculations where each step builds directly on the result of the previous.
  • Simple and predictable tasks
    • Since single-threads are linear, programs made with single-threads will be simpler to write, design, and debug. Flow of operations will also be clear and predictable.
  • Single-core processors
    • If you are working on systems with only one CPU core, single-threads will execute equal to or faster than multi-threads. This is because there is overhead1 when switching between different threads.

Example code:

public class SingleThread {
    public static void main(String[] args) {
        System.out.println("Task 1: Starting...");
        try { Thread.sleep(1000); } catch (InterruptedException e) {}
        System.out.println("Task 1: Done.");

        System.out.println("Task 2: Starting...");
        try { Thread.sleep(1000); } catch (InterruptedException e) {}
        System.out.println("Task 2: Done.");
    }
}

Here, Task 1 must complete(there’s a 1 second wait) before Task 2 can begin.

What are multi-threads?

In a multi-threaded program, the application operates with multiple workers(threads). Since there are multiple workers, each worker can be assigned with different tasks, meaning that tasks can be processed simultaneously.

When should I use multi-threading?

  • Less orderly tasks
    • Programs that doesn’t require sequential execution, such as downloading multiple images for a webpage or performing multiple different background operations. Programs that prioritize speed over everything.
  • Multi-core processors
    • If you use multi-threaded operations on multi-core processors, different threads can genuinely execute simultaneously on separate CPU cores. This means that tasks will complete much faster than a single core.
  • I/O2-bound tasks
    • When a task frequently enters a waiting state (ex, waiting for user input), a multi-threaded operation will allow allow other threads to continue active processing instead of just waiting.

Example code:

public class MultiThread extends Thread {
    private String taskName;
    private int sleepTime;

    public MultiThread(String taskName, int sleepTime) {
        this.taskName = taskName;
        this.sleepTime = sleepTime;
    }

    public void run() {
        System.out.println(taskName + ": Starting...");
        try { Thread.sleep(sleepTime); } catch (InterruptedException e) {}
        System.out.println(taskName + ": Done.");
    }

    public static void main(String[] args) {
        MultiThread task1 = new MultiThread("Task 1", 1000);
        MultiThread task2 = new MultiThread("Task 2", 1000);
        task1.start();
        task2.start();
    }
}

Here, task1.start() and task2.start() launch two threads that run simultaneously. task2.start() doesn’t wait until task1.start() is finished operating(which would take 1000 milliseconds).

Relationship between cores and threads

To anyone reading through this post, I wish one of the big takeaway is that you understand the relationship between cores and threads. To sum everything about cores and threads up, if there are just one core, using single-threads will be more efficient. On the other hand, if there are multiple cores, it’ll be better to use multiple threads that correlate to the number of cores.

Then what happens if there are more threads than cores?

If there are more threads than cores, it’s not that the system will just stop operating.

For example, (X)# of threads in (X-n) # of cores is still possible. However, what going to happen is that some threads will ‘take turns’ on the same CPU. This is called “context switching.”

During context switching, each thread takes certain intervals of time, then switch to one another. During this interval, each thread completes a bit of their own respective tasks.

Another thing to note is that context switching is happening in your computer all the time. For example, according to a reddit comment, if you have your chrome tab open to one side playing a song, and a google doc open to the other, what your computer is doing is FURIOUSLY switching back and forth between the two to make it appear as if both programs are running simultaneously.

  1. Overhead refers to the extra resources, like CPU time and memory, consumed by the system when managing tasks. In this context, it’ll be the resources consumed when switching between threads. ↩︎
  2. I/O operation means input/output operations. These refer to any operations where a program reads data from or writing data to an external device. For example, if you type a command in a terminal, that’s considered an input. If the computer then displays information regarding the user input, that’s the output. ↩︎

Leave a Reply

Your email address will not be published. Required fields are marked *