Java provides mechanisms to control how threads are executed by the JVM using thread priorities and daemon threads. These features allow developers to influence thread scheduling and background task behavior, which is vital in responsive UIs, batch processing, and system services.
In this guide, we’ll explore what priorities and daemon threads are, how they work, and how to use them effectively in real-world applications.
What Are Thread Priorities?
Each thread in Java has a priority ranging from 1 (MIN_PRIORITY) to 10 (MAX_PRIORITY), with 5 (NORM_PRIORITY) as the default.
Thread t = new Thread(() -> {
System.out.println("Thread running");
});
t.setPriority(Thread.MAX_PRIORITY);
- Higher-priority threads are more likely to be scheduled before lower-priority ones.
- But JVMs do not guarantee strict priority-based scheduling.
Thread Priority Constants
Constant | Value | Description |
---|---|---|
MIN_PRIORITY | 1 | Lowest priority |
NORM_PRIORITY | 5 | Default priority |
MAX_PRIORITY | 10 | Highest priority |
Real-World Analogy: Priority
Imagine an airport check-in:
- MAX_PRIORITY → First-class passengers
- MIN_PRIORITY → Economy-class
- But during rush hour, even first-class may wait — just like JVM thread schedulers.
Daemon Threads: What Are They?
A daemon thread is a background thread that does not prevent the JVM from exiting.
Thread daemon = new Thread(() -> {
while (true) {
System.out.println("Running background task...");
}
});
daemon.setDaemon(true);
daemon.start();
- JVM shuts down when only daemon threads remain.
- Common use cases:
- GC thread
- Monitoring/logging
- Cleanup utilities
Rules for Daemon Threads
- Must be set before calling
start()
- Inherited from parent thread if not explicitly set
- Should not perform critical tasks (no guaranteed completion)
Thread Lifecycle Recap
NEW → RUNNABLE → RUNNING → WAITING/BLOCKED → TERMINATED
- Both priority and daemon status affect the behavior during the RUNNABLE → RUNNING stage.
Example: Mixing Priorities and Daemons
Thread high = new Thread(() -> {
for (int i = 0; i < 5; i++) System.out.println("High priority");
});
Thread low = new Thread(() -> {
for (int i = 0; i < 5; i++) System.out.println("Low priority");
});
high.setPriority(Thread.MAX_PRIORITY);
low.setPriority(Thread.MIN_PRIORITY);
high.start();
low.start();
Note: Results may vary per JVM/os.
Java Internals and Memory Model
- Thread priority is a hint to the JVM scheduler
- Daemon status affects the termination policy
volatile
,synchronized
, and coordination tools behave the same regardless of daemon status
Thread Coordination Tools
join()
waits for any thread, daemon or notsleep()
,wait()
affect all threads equally- Daemon threads should not block indefinitely without yielding
Real-World Use Cases
- Daemon threads for background logging
- Priority threads for handling critical I/O faster
- UI responsiveness via background data fetch (low priority)
Java Version Tracker
📌 What's New in Java Versions?
Java 8
- Lambda support for Runnable
CompletableFuture
for async flows
Java 9
- Flow API for reactive backpressure
Java 11+
- Better
CompletableFuture
tuning
Java 21
- Virtual threads inherit daemon status
- Structured concurrency provides better lifecycle management
- Scoped values improve context passing
Best Practices
- Avoid relying on thread priorities for correctness
- Always
setDaemon(true)
before callingstart()
- Never use daemon threads for database commits, file writes, etc.
- Monitor threads using profiling tools for stuck daemons
Common Pitfalls
- Forgetting to set daemon before
start()
→ runtime exception - Assuming priority guarantees execution order
- Using daemon threads for critical business logic
- Daemons silently dying due to unhandled exceptions
Design Patterns Involving Priorities and Daemons
- Background Workers
- Watchdog Monitors
- Priority Task Executors
Conclusion and Key Takeaways
- Thread priorities influence scheduling, not guarantee it
- Daemon threads are useful for background, non-critical services
- Always design thread logic to be robust regardless of JVM scheduling policies
- Use structured concurrency and virtual threads for modern scalable solutions
FAQs
Q1: Can I change priority after starting a thread?
A: Yes, but it may not take effect immediately.
Q2: What happens if a daemon thread is running when the JVM exits?
A: It is stopped immediately without cleanup.
Q3: Do virtual threads support priorities?
A: No. Virtual threads ignore traditional thread priority.
Q4: Can a thread be both high priority and daemon?
A: Yes. They are orthogonal properties.
Q5: Should I always use daemon threads for background tasks?
A: Only if the task is not mission-critical.
Q6: Can I monitor daemon threads?
A: Yes, using Thread.isDaemon()
or monitoring tools.
Q7: Is Thread.MIN_PRIORITY
always lowest on every OS?
A: No. JVM maps these values to OS-specific priority levels.
Q8: Do thread pools use daemon threads?
A: No, by default threads in thread pools are non-daemon.
Q9: What is a non-daemon thread?
A: Any thread that keeps the JVM alive until it completes.
Q10: How to gracefully stop daemon threads?
A: Use a shared volatile
flag or interrupt()
check inside the loop.