14.2. Thread Terminology

14.2.1. Working Definitions

thread

A thread is a sequence of instructions emitted by executing a method.

main thread The thread for instructions emitted by the

main method.

14.2.2. Parallel Execution

When a program runs on a computer, its instructions are sent by the operating system to the computer’s central processing unit (or CPU) where the execution of those instructions actually takes place. Early CPUs could only execute a single sequence of instructions at any given time; however, modern CPUs are built with multiple internal processing units, each of which is called a core, that can each run their own sequence of instructions in parallel (i.e., at the same time) with all the other cores.

The example in the diagram below illustrates the parallel execution of a main thread and another thread named t1. Each vertical line is a timeline that starts at the top and ends at the bottom, and the rectangular areas along the line illustrate when the instructions in a thread are executing on some core. Since the rectangular areas for each thread overlap some regions of time along the timeline, they are executing in parallel.

digraph G {

  node [shape=box style=filled fillcolor=white];
  edge [arrowhead="none"];

  subgraph main {
    main     [label="main"];
    main_0   [fixedsize=true width=0.15 height=2 label=""];
    main_end [shape=point];

    main -> main_0 -> main_end;
  }

  subgraph t1 {
    t1       [label="t1"];
    t1_0     [fixedsize=true width=0.15 height=1 label=""];
    t1_end   [shape=point];

    t1 -> t1_0 -> t1_end;
  }

}

Example of Parallel Execution

14.2.3. Concurrent Execution

When the number of instruction sequences exceeds the number of cores, the operating can still give the appearance that they are executing at the same time by switching between those instruction sequences very quickly, sending a little bit of each sequence to a core for execution at any given time. Since these sequences are not actually executing in parallel but still appear to be, we call this concurrent execution.

The example in the diagram below illustrates the concurrent execution of a main thread and another thread named t1. Each vertical line is a timeline that starts at the top and ends at the bottom, and the rectangular areas along the line illustrate when the instructions in a thread are executing on some core. Since the rectangular areas for each thread never overlap, they are said to be executing concurrently so long as the operating system is switching between them really fast.

digraph G {

  graph [ranksep=0]

  node [shape=box style="filled rounded" fillcolor=white] main t1;

  node [shape=box style=filled fixedsize=true width=0.15 label=""]
    main_0 main_2 main_4
    t1_1 t1_3;

  node [shape=point] main_end t1_end;

  node [shape=plaintext style=filled fillcolor=black fixedsize=true width=0.015 label=""]
    main_1 main_3;

  edge [arrowhead="none"];

  main -> main_0 -> main_1 -> main_2 -> main_3 -> main_4 -> main_end;
    t1 ->   t1_0 ->   t1_1 ->   t1_2 -> t1_3   -> t1_end;

}

Example of Concurrent Execution

In practice, programs involving several threads execute concurrently most of the time and in parallel some of the time, depending on which core the operating system sends the subsequences of the thread’s instructions to.

14.2.4. Additional Notes

Most operating systems use processes to represent and store the instructions and state of a running program in order to facilitate their concurrent execution – it gives the operating a set of objects to switch between. Likewise, programs that need to facilitate concurrent execution of different parts of the program typically use threads to represent and store the instructions and state of a running method (and its calls to other methods) – it gives the program a set of objects that can also be switched between.

On a Unix machine, you can typically use the ps command to list the processes that the operating system is currently managing and switching between:

Example: Using ps to list the processes currently managed by the operating system that have not yet terminated.
ps -e
  PID TTY          TIME CMD
    1 ?        01:51:39 systemd
    2 ?        00:00:40 kthreadd
    4 ?        00:00:00 kworker/0:0H
    6 ?        00:00:47 ksoftirqd/0
    7 ?        00:00:15 migration/0
    8 ?        00:00:00 rcu_bh
    9 ?        02:02:48 rcu_sched
   10 ?        00:00:00 lru-add-drain
   11 ?        00:00:34 watchdog/0
   ...
   [typically continues for hundreds lines]

To count the number of processes, you can pipe the output into wc to see how many lines are produced. In the example below, the output suggests that there are 743 processes managed by the operating system that have not yet terminated – we subtract one to account for the header line produced by ps:

Example: Using wc to count the number of lines displayed by ps.
ps -e | wc -l
744

To see extended information about the process managed by the operating system that were started by your user account but have not yet terminated, use the -x option with ps:

Example: Using ps to see the processes that you started that have not yet terminated.
ps -x
  PID TTY      STAT   TIME COMMAND
 5973 ?        S      0:00 sshd: myid@pts/48
 5974 pts/48   Ss     0:00 -bash
27886 pts/48   R+     0:00 ps -x

In the last example, sshd is handling the the SSH connection for the user, -bash is their login shell, and ps -x is the instance of ps that is being run to produce the output (i.e., ps includes itself in its output).