What is concurrency.
Programs do not always run one step at a time. Sometimes multiple things happen at once. A web server handles many users. A phone plays music while you browse. This is concurrency. Today we understand what concurrency means and why it matters.
Most code executes sequentially.
One instruction finishes. The next begins. Step by step. In order.
This is simple to understand. You read code top to bottom. That is the order things happen.
Sequential execution is predictable. Given the same input, you get the same sequence of events.
But sequential has limits. If task A takes 5 seconds and task B takes 3 seconds, running them sequentially takes 8 seconds. You must wait.
What if task A is waiting for network response? The CPU sits idle while waiting. Wasted potential.
Concurrency means multiple tasks make progress in overlapping time.
Task A starts. Before it finishes, task B starts. Both are in progress. They might switch back and forth, or they might run truly simultaneously.
Concurrency does not mean simultaneous. It means overlapping. While A waits for network, B can run. When B waits for disk, A can resume.
This is like cooking dinner. You do not wait for water to boil before preparing vegetables. You start the water, then prepare vegetables while waiting. Multiple tasks, overlapping progress.
Concurrency is about dealing with multiple things at once, not necessarily doing them at once.
These terms are related but different.
Concurrency is about structure. Organizing a program to handle multiple tasks that can be in progress.
Parallelism is about execution. Actually running multiple computations at the same instant on multiple processors.
Concurrency is possible on a single CPU. The processor switches between tasks. Only one runs at any instant, but many make progress over time.
Parallelism requires multiple CPUs or cores. Multiple instructions truly execute simultaneously.
All parallel programs are concurrent. Not all concurrent programs are parallel.
A web server can be concurrent even on one core. It handles many connections by switching between them. Add more cores, and it becomes parallel too.
Responsiveness. A user interface must respond even while background work happens. Without concurrency, the UI freezes during computation. With concurrency, computation happens alongside user interaction.
Throughput. A server can handle more requests if it does not wait for each to complete. While one request waits for database, another request gets processed.
Resource utilization. CPUs are fast. Networks and disks are slow. If you wait for I/O, the CPU idles. Concurrency keeps the CPU busy while waiting for I/O elsewhere.
Real-world modeling. The world is concurrent. Users, sensors, services act independently. Concurrent programs model this naturally.
Concurrency enables systems that scale, respond, and efficiently use resources.
Concurrency is hard.
Non-determinism. The order of operations across concurrent tasks is not fixed. Run the same program twice, get different orderings. Debugging becomes difficult.
Race conditions. Two tasks access the same data. The result depends on who gets there first. Bugs that appear and disappear randomly.
Coordination. Tasks must sometimes wait for each other. Task B needs the result of task A. Managing this coordination is tricky.
Reasoning. Sequential code is one story. Concurrent code is multiple interleaved stories. Your brain must track all possibilities.
These problems are not insurmountable. But they require new thinking. You must design for concurrency, not bolt it on.
Think of concurrent execution as interleaving.
Task A has steps A1, A2, A3. Task B has steps B1, B2, B3.
Possible orderings: A1, A2, A3, B1, B2, B3. Or A1, B1, A2, B2, A3, B3. Or B1, A1, A2, B2, B3, A3. Many possibilities.
With concurrency, any valid interleaving might happen. Your program must work correctly for all of them.
This is the fundamental challenge. You cannot assume a specific ordering. You must handle any ordering.
When a specific ordering is required, you must enforce it explicitly. Otherwise, the system chooses freely.
Another way to think: multiple timelines.
Each concurrent task is its own timeline. Events happen along each timeline. Where timelines interact, coordination is needed.
Sequential code is one timeline. Easy to follow.
Concurrent code is multiple timelines that occasionally merge. When they merge, whose version wins? What happens if they conflict?
Drawing timelines helps visualize concurrency. Time goes left to right. Each task is a horizontal line. Interactions are vertical connections.
When timelines touch, problems can occur. Keeping timelines independent is safer. When they must touch, do so carefully.
Concurrency affects how you write code.
Shared state becomes dangerous. If two tasks read and write the same variable, chaos ensues. You must protect shared state or avoid it.
Testing is harder. You cannot easily reproduce bugs that depend on timing. Tests might pass 99 times and fail once.
Logging helps. When things go wrong, logs show what happened and when. Include timestamps and task identifiers.
Design matters more. Poor concurrent design leads to bugs that are hard to find and fix. Good design prevents problems before they occur.
Let us summarize.
Sequential execution is simple but limited. One thing at a time.
Concurrent execution is multiple tasks making progress in overlapping time.
Concurrency is about structure. Parallelism is about simultaneous execution.
Concurrency enables responsiveness, throughput, and resource utilization.
Concurrency introduces complexity: non-determinism, race conditions, coordination.
Think of concurrent execution as interleaving or multiple timelines.
Concurrency requires careful design. The payoff is systems that scale and respond.