Thread Priorities and Daemon Threads in Java Explained with Real Examples

Illustration for Thread Priorities and Daemon Threads in Java Explained with Real Examples
By Last updated:

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 not
  • sleep(), 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 calling start()
  • 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.