Let's begin by introducing the star of the show, the thread. The following is probably more accurately considered a description rather than a definition, even though it reads a little like the latter.
A thread is a sequential flow of control with its own program counter and call stack. It shares state, memory and resources with other threads in the same process. Since each thread gets its own call stack, local variables aren't shared. Instance and class variables, however, are shared across threads. It's also possible to define variables that exist outside of methods but are still local to a specific thread, and these are called thread-local variables.
OK, so that's what a thread is. What can we do with them?
In software development we're asked to solve different kinds of problem. We may be asked to write code that takes a bunch of information about a loan applicant and produces a verdict as to whether that applicant should get the loan. Maybe we have to write a web-based shopping cart. Or maybe we have to write code to make a guy's arms and legs flail about in a realistic fashion when he falls off a cliff in a video game.
For any given problem there are typically multiple ways to solve it, and different ways to categorize the solutions. One useful way of distinguishing solutions is to separate serial from parallel solutions. Let's look at that distinction in more detail.
Some problems have solutions that are essentially a single series of steps. If you're writing a home affordability calculator, for example, the steps might be as follows:
Our recipe for solving the "home affordability problem" is said to be serial because it's essentially just a series of steps to carry out. We might even go so far as to describing the problem itself as a serial problem, which is just a shorthand way of saying that the most plausible and reasonable solutions to the problem are serial solutions. Either way, the essence of serialism is that we have a series of steps that a single control flow can carry out.
Now let's look at the alternative to serialism, which would be parallelism.

Some problems are amenable to solutions involving multiple concurrent control flows, which is to say that they have parallel solutions. To take a non-computing example, say you have a room with toys scattered all over the floor. You want the room clean. As potential participants to the cleanup effort you have yourself and three kids. A possibly-relevant piece of background information is that one child is entirely responsible for the mess.
Readers with young children will no doubt recognize this classic problem from the field of parenting algorithms. Fortunately, well-known serial and parallel solutions are available. The best approach in any given case depends strongly upon your goals:
Whether we're talking about serialism or parallelism, there is a recurring concept, which is that of a flow of control. In the serial case we have exactly one flow. In the parallel case we have more.
Computer scientists, hardware engineers and software engineers spend a lot of time with the distinction between serialism and parallelism. Let's look at why that is.
In a word, performance. In many cases—not all, but many—parallel solutions are simply faster than serial solutions, owing to the "many hands make light work" effect. And from a practical perspective, that's the main reason we care about concurrency (i.e., parallelism) despite its many attendant complications.
The rest of this article explains what some of those complications are and some ways to overcome them.