What Are the Different Types of Concurrency?

The main types of concurrency are thread-based, process-based and event-driven (asynchronous) concurrency, each of which can be preemptive or cooperative, and each of which can split work by data or by task. Two more categories appear in specific settings: distributed concurrency across machines, and concurrency control inside databases, which is either optimistic or pessimistic.

Concurrency means that several tasks are in progress during the same period. Parallelism means that several tasks execute in the same instant on different cores. A single-core machine can be concurrent but never parallel. An 8-core machine running 8 threads is both.

The types in one table

TypeUnit of workShares memory?Who switchesExample
Thread-basedThread inside a processYesOS scheduler (preemptive)A web server with a pool of 200 worker threads
Process-basedSeparate processNo, uses pipes or socketsOS scheduler (preemptive)PostgreSQL, one process per connection
Event-driven (async)Task or coroutine on an event loopYesThe task itself, at await (cooperative)Node.js, Python asyncio, browser JavaScript
Data parallelismSame operation on chunks of dataUsually yesRuntime or librarySumming a large array with one thread per chunk
Task parallelismDifferent operations at onceUsually yesRuntime or libraryCompressing one file while encrypting another
DistributedProcess on another machineNo, uses the networkEach machine's own schedulerA microservice calling three other services
Real-timeTask with a deadlineVariesPriority schedulerEngine control unit in a car

Thread-based, process-based and event-driven

Thread-based concurrency runs several threads inside one process. They share the same heap, so passing data is free, and so is corrupting it. A thread that writes to a map while another reads it produces a data race. Locks, atomics and thread-safe collections exist to prevent that. Java, C++, C# and Go programs use this model most of the time.

Process-based concurrency runs several processes, each with its own memory. A crash or a memory leak in one process does not affect the others, and there are no data races. Communication costs more, because data has to be copied through a pipe, a socket or shared memory. Python uses processes for CPU-bound work because of its global interpreter lock, and PostgreSQL uses one process per client connection.

Event-driven concurrency runs many tasks on one thread with an event loop. A task runs until it needs to wait, typically for a network reply, and then yields. The loop runs another task in the meantime. There is no parallelism on a single loop, but there is also no lock contention, and tens of thousands of idle connections cost almost nothing. Node.js, nginx and Python asyncio are built this way.

Preemptive and cooperative concurrency

In preemptive concurrency, the scheduler can interrupt a task at any point. Operating system threads work this way. A task cannot starve the others by running forever, but any line of code may be interrupted, so shared data needs locks.

In cooperative concurrency, a task runs until it yields. Coroutines and async functions work this way: the only switch points are the await expressions. Code between two awaits cannot be interrupted, which removes many locks. The cost is that one long computation without an await blocks every other task on that loop.

Data parallelism and task parallelism

Data parallelism applies the same operation to many pieces of data at once. Rendering an image splits the pixels across threads. A parallel sort splits the array. GPUs are data-parallel machines with thousands of small cores. The work divides evenly, so the speedup is close to the core count.

Task parallelism runs different operations at the same time. A build tool compiles one file while it links another. A game runs physics on one thread and audio on another. The tasks differ in length, so one long task can leave other cores idle.

Distributed and real-time concurrency

Distributed concurrency spreads tasks across machines that talk over a network. Nothing is shared, messages can be lost or delayed, and any machine can fail while the others continue. The problems change from data races to partial failure, ordering and consensus.

Real-time concurrency adds deadlines. A hard real-time task, such as a brake controller, must finish within its deadline every time, and the scheduler is chosen to guarantee that. A soft real-time task, such as video playback, may miss an occasional deadline with reduced quality.

Concurrency control in databases: optimistic and pessimistic

Databases face concurrency from many clients writing the same rows. Pessimistic concurrency control locks a row before reading it, so a second writer waits. It is safe under heavy contention but reduces throughput. Optimistic concurrency control lets everyone proceed and checks for conflicts at commit time, usually by comparing a version number. If the version changed, the write is rejected and the client retries.

MongoDB's WiredTiger storage engine uses optimistic concurrency control internally, with document-level conflict detection and a transparent retry. At the application level, the same pattern is a version field in the document.

db.orders.updateOne( { _id: orderId, version: 7 }, { $set: { status: "shipped" }, $inc: { version: 1 } } )

If matchedCount is 0, another writer changed the document first, and the application reads it again before retrying.

How to Prepare

Interviewers use this question to check whether you can pick a model for a given problem, not to hear the list.

  • Match each type to one problem it fits. Threads for a CPU-bound server, an event loop for many idle connections, processes for isolation, optimistic control for low-conflict database writes.
  • Explain the trade-off in each pair. Preemptive against cooperative, threads against processes, optimistic against pessimistic.
  • Code one of them. A bounded queue with two threads is the most common request.

Grokking Multithreading and Concurrency for Coding Interviews covers the thread-based model in depth with coded exercises.

Grokking System Design Fundamentals covers distributed concurrency and database concurrency control.

Grokking the System Design Interview applies both to full system design questions.

TAGS
Coding Interview
CONTRIBUTOR
Arslan Ahmad
Arslan Ahmad
ex-FAANG engineering manager and author or Grokking series.

GET YOUR FREE

Coding Questions Catalog

Design Gurus Newsletter - Latest from our Blog
Boost your coding skills with our essential coding questions catalog.
Take a step towards a better tech career now!
Explore Answers
Where to position the camera for Zoom?
What does a UX interview look like?
What is oops in C++?
Why is Microsoft not in FAANG?
What is the best programming language to learn for interviews?
What type of tool is Twilio?
Related Courses
New
Grokking the AI System Design Interview course cover
Grokking the AI System Design Interview
Learn to design AI systems the way interviewers expect: classic ML products, LLM and RAG architectures, and agentic systems, all through the lens of the system design interview.
4.6
(3,192 learners)
Discounted price for Your Region

$99

Grokking the Coding Interview: Patterns for Coding Questions course cover
Grokking the Coding Interview: Patterns for Coding Questions
The 24 essential patterns behind every coding interview question. Available in Java, Python, JavaScript, C++, C#, and Go. The most comprehensive coding interview course with 543 lessons. A smarter alternative to grinding LeetCode.
4.6
Discounted price for Your Region

$197

Grokking Modern AI Fundamentals course cover
Grokking Modern AI Fundamentals
Master the fundamentals of AI today to lead the tech revolution of tomorrow.
4.1
Discounted price for Your Region

$72

Design Gurus logo
One-Stop Portal For Tech Interviews.
About Us
Our Team
Careers
Partners
Contact Us
Become Affiliate
Copyright © 2026 Design Gurus, LLC. All rights reserved.