Lecture from: 27.02.2024 | Video: Video ETHZ

Java Threads

Java Threads: Key Points

  • Every Java program has at least one thread (the main thread).
  • start() creates an actual execution thread.
  • A program ends when all non-daemon (= user thread, keeps running until execution finishes) threads finish.
  • Threads can continue to run even if main() returns.
  • Creating a Thread object does not start a thread; calling run() directly also does not start a new thread.

Useful Thread Attributes and Methods

  • ID: A unique identifier for each thread.
  • Name: A string name for the thread (can be set).
  • Priority: A numerical priority (1-10) that influences scheduling.
  • Status: The current state of the thread (NEW, RUNNABLE, BLOCKED, etc.).

Using Thread States and Priorities

This example demonstrates setting thread priorities and monitoring thread states.

Observations: threads are often blocked due to I/O, and higher-priority threads tend to finish before lower-priority threads.

Joining Threads

A common scenario is a main thread spawning worker threads and then needing to wait for their results. Busy waiting (repeatedly checking the state of worker threads) is inefficient.

The join() method provides a better solution. A thread calling thread.join() will block until the thread object terminates.

Performance Trade-off: join() incurs context switch overhead. If worker threads are very short-lived, busy waiting might be faster (but generally, join() is preferred).

Exceptions

In a single-threaded program, an uncaught exception terminates the program. In a multithreaded program, an exception thrown in a worker thread:

  • Is usually shown on the console.
  • Does not affect the behavior of thread.join().
  • May not be noticed by the main thread.

Setting UncaughtExceptionHandlers

The UncaughtExceptionHandler interface allows you to handle unchecked exceptions in threads. You can register a handler:

  • With a specific Thread object.
  • With a ThreadGroup object.
  • Globally for all threads using setDefaultUncaughtExceptionHandler().

Shared Resources

Analogy: threads “fighting” over the console.

Synchronized Incrementing and Decrementing

This example shows two threads (one incrementing, one decrementing) a shared counter. The results are unpredictable because the increment/decrement operation (this.value += delta;) is not atomic. It’s executed in multiple bytecode instructions.

Relevant bytecode for increment operation:

Continue here: 05 Introduction to Threads and Synchronization (Part III)