How Dart Handles Multi-threading with Isolates #
1. The Concept #
Unlike many programming languages that use threads for concurrency, Dart uses Isolates.
An Isolate is an independent unit of execution that has its own:
- Memory heap
- Event loop
- Single-threaded execution model
That means:
- No shared memory between isolates.
- Communication happens through message passing (similar to the actor model).
This design avoids typical multi-threading issues like race conditions and deadlocks.
2. Why Isolates Instead of Threads #
Dart’s single-threaded event loop model (especially in Flutter apps) keeps the UI smooth.
However, for heavy computations (like parsing large JSON, image processing, or encryption), the main isolate (UI thread) can get blocked.
To prevent this, Dart allows you to spawn a new isolate to handle the heavy work on another CPU core — without blocking the main isolate.
3. Communication Between Isolates #
Isolates do not share memory, so they communicate by sending messages through ports:
- SendPort – used to send data.
- ReceivePort – used to receive data.
Example:
import 'dart:isolate';
void heavyTask(SendPort sendPort) {
int result = 0;
for (int i = 0; i < 100000000; i++) {
result += i;
}
sendPort.send(result);
}
void main() async {
final receivePort = ReceivePort();
// Spawn a new isolate
await Isolate.spawn(heavyTask, receivePort.sendPort);
// Listen for message
receivePort.listen((message) {
print('Result: $message');
receivePort.close();
});
}
Here:
- The main isolate spawns a new isolate to run
heavyTask. - The child isolate sends the result back using the
SendPort.
