CodeGym /Courses /JAVA 25 SELF /Thread parameters and priorities

Thread parameters and priorities

JAVA 25 SELF
Level 51 , Lesson 3
Available

1. Passing parameters to threads

When you start a thread, you often want to pass it some “work”: a file name, a range of numbers, or a greeting. A thread without parameters is like a courier without an address: he runs around the city but doesn’t know where to deliver the pizza.

How do you do that?

In Java, threads are typically created in two ways:

  • Subclassing Thread
  • Implementing the Runnable interface (or using a lambda expression)

Parameters are most often passed via the constructor of the class that implements Runnable. It’s simple, safe, and clear. Make the fields final—and you protect the parameters from changes by other threads. Using setters/public fields is fraught with synchronization issues.

Example 1: A thread with a parameter via a constructor

Let’s improve a sample app: process user orders in a separate thread.

public class OrderProcessor implements Runnable {
    private final String orderId;

    public OrderProcessor(String orderId) {
        this.orderId = orderId;
    }

    @Override
    public void run() {
        System.out.println("Processing order: " + orderId + " in thread " + Thread.currentThread().getName());
        // Long processing may happen here...
    }
}

Create and start threads:

public class Main {
    public static void main(String[] args) {
        Thread thread1 = new Thread(new OrderProcessor("ORDER-001"));
        Thread thread2 = new Thread(new OrderProcessor("ORDER-002"));
        thread1.start();
        thread2.start();
    }
}

Expected output:

Processing order: ORDER-001 in thread Thread-0
Processing order: ORDER-002 in thread Thread-1

Example 2: A thread with a parameter via a lambda expression (Java 8+)

If the task is simple, you can do without a separate class.

public class Main {
    public static void main(String[] args) {
        String user1 = "John";
        String user2 = "Kate";

        Thread thread1 = new Thread(() -> {
            System.out.println("Hello, " + user1 + " from " + Thread.currentThread().getName());
        });

        Thread thread2 = new Thread(() -> {
            System.out.println("Hello, " + user2 + " from " + Thread.currentThread().getName());
        });

        thread1.start();
        thread2.start();
    }
}

Why shouldn’t you use setters/getters to pass parameters?
If you pass parameters via setters or public fields, you risk another thread changing the value right during execution. This can lead to hard-to-catch bugs. It’s better to make fields final and pass them via the constructor.

2. Thread priorities

In Java, each thread has a priority—an integer from 1 to 10 that tells the scheduler how “important” the thread is compared to others. By default, all threads have priority 5 (Thread.NORM_PRIORITY).

Important: a priority is only a “hint” to the OS. It’s not a guarantee that a thread with priority 10 will run faster than a thread with priority 1. It all depends on the OS, its settings, and current load.

How to set a thread’s priority?

The Thread class has methods:

  • setPriority(int newPriority)
  • getPriority()

And three standard constants:

  • Thread.MIN_PRIORITY (1)
  • Thread.NORM_PRIORITY (5)
  • Thread.MAX_PRIORITY (10)

Example 3: Setting a thread’s priority

public class PriorityDemo {
    public static void main(String[] args) {
        Runnable task = () -> {
            System.out.println("Thread " + Thread.currentThread().getName() +
                    " with priority " + Thread.currentThread().getPriority());
        };

        Thread low = new Thread(task, "LowPriority");
        Thread norm = new Thread(task, "NormalPriority");
        Thread high = new Thread(task, "HighPriority");

        low.setPriority(Thread.MIN_PRIORITY);    // 1
        norm.setPriority(Thread.NORM_PRIORITY);  // 5
        high.setPriority(Thread.MAX_PRIORITY);   // 10

        low.start();
        norm.start();
        high.start();
    }
}

Expected output (line order is not guaranteed!):

Thread LowPriority with priority 1
Thread HighPriority with priority 10
Thread NormalPriority with priority 5

Does priority affect execution order?

In most cases—no. Priorities can influence how much CPU time a thread gets, but they don’t guarantee start or finish order. Don’t build your program’s logic on priorities—use them as “soft” hints, for example, so a background thread doesn’t interfere with the main one.

Table: Thread priority constants

Constant Value Description
Thread.MIN_PRIORITY
1 Lowest priority
Thread.NORM_PRIORITY
5 Normal priority
Thread.MAX_PRIORITY
10 Highest priority

3. Naming threads

A thread name is a “nickname” in the multitasking world. When you have dozens of threads, debugging is easier if, instead of "Thread-7" in the log, you see "FileUploader-1". This is especially important when analysing logs and looking for bugs.

How to set a thread’s name?

You can specify the name directly in the Thread constructor or set it with setName. Get the current name with getName.

Thread t = new Thread(() -> {
    System.out.println("I'm working!");
}, "MyThreadName");
t.start();

Example 4: Named threads

public class NamedThreads {
    public static void main(String[] args) {
        Thread threadA = new Thread(() -> {
            System.out.println("I am a thread: " + Thread.currentThread().getName());
        }, "Downloader");

        Thread threadB = new Thread(() -> {
            System.out.println("I am a thread: " + Thread.currentThread().getName());
        });
        threadB.setName("Uploader");

        threadA.start();
        threadB.start();
    }
}

Expected output:

I am a thread: Downloader
I am a thread: Uploader

4. Practice: multiple threads with different parameters, priorities, and names

Let’s put it all together in one example: each order is a separate thread with its own name and priority.

public class OrderProcessor implements Runnable {
    private final String orderId;
    private final int processingTimeMs;

    public OrderProcessor(String orderId, int processingTimeMs) {
        this.orderId = orderId;
        this.processingTimeMs = processingTimeMs;
    }

    @Override
    public void run() {
        System.out.println("[" + Thread.currentThread().getName() + "] Started processing order " + orderId +
                " (priority " + Thread.currentThread().getPriority() + ")");
        try {
            Thread.sleep(processingTimeMs); // simulate work
        } catch (InterruptedException e) {
            System.out.println("[" + Thread.currentThread().getName() + "] Interrupted!");
        }
        System.out.println("[" + Thread.currentThread().getName() + "] Finished processing order " + orderId);
    }

    public static void main(String[] args) {
        Thread fastOrder = new Thread(new OrderProcessor("FAST-ORDER", 500), "FastOrderThread");
        Thread normalOrder = new Thread(new OrderProcessor("NORMAL-ORDER", 1000), "NormalOrderThread");
        Thread slowOrder = new Thread(new OrderProcessor("SLOW-ORDER", 2000), "SlowOrderThread");

        fastOrder.setPriority(Thread.MAX_PRIORITY);
        normalOrder.setPriority(Thread.NORM_PRIORITY);
        slowOrder.setPriority(Thread.MIN_PRIORITY);

        fastOrder.start();
        normalOrder.start();
        slowOrder.start();
    }
}

What we’ll see:

  • Each thread prints which order it processes, its name, and its priority.
  • Processing time is simulated using Thread.sleep.
  • The completion order of threads may not match their priority.

5. Important nuances and details

Passing parameters: use the constructor only!

It’s safer. Declare parameters as final—they can’t be changed after the object is created, and no other thread will “sneak in” its own values. This is critical to preventing data races.

Priorities: don’t build business logic on them

Priorities are like asking a waiter: “Can I get my coffee faster?” Sometimes it works, sometimes it doesn’t. It’s a recommendation to the OS, not an execution rule.

Thread names: use them for debugging

They save a huge amount of time when analysing logs. Get used to assigning meaningful names right away.

6. Common mistakes when working with thread parameters and priorities

Mistake #1: Passing parameters through public fields. If you declare parameters as regular fields and change them after the thread starts, you can get unpredictable results. Use final fields and a constructor.

Mistake #2: Expecting that priority guarantees order. You set Thread.MAX_PRIORITY and think the thread will always be first? No. Don’t use priorities for synchronization or logic control.

Mistake #3: Unnamed threads in logs. When logs only have “Thread-3”, “Thread-7”, it’s hard to find the culprit. Give threads meaningful names using the constructor or setName.

Mistake #4: Using the same Runnable object for multiple threads. If a Runnable object holds state and you pass it to multiple threads, they “share” parameters—a straight road to data races. Create a separate Runnable per thread.

Mistake #5: Passing parameters via set-methods. If you set parameters through set* methods after the thread has been created/started, values can change “on the fly”—a classic race condition.

1
Task
JAVA 25 SELF, level 51, lesson 3
Locked
Managing agents in an online marketplace 🛍️
Managing agents in an online marketplace 🛍️
1
Task
JAVA 25 SELF, level 51, lesson 3
Locked
Coordinating Robots at a Smart Factory 🏭
Coordinating Robots at a Smart Factory 🏭
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION