Backend Development 9 min read

Understanding Java Processes, Threads, and Thread Creation Techniques

The article clarifies Java processes and threads using a game analogy, then demonstrates three thread‑creation techniques—extending Thread, implementing Runnable, and implementing Callable with FutureTask—while covering run vs start, thread control methods such as sleep, join, and daemon settings.

Java Tech Enthusiast
Java Tech Enthusiast
Java Tech Enthusiast
Understanding Java Processes, Threads, and Thread Creation Techniques

For Java beginners, many multithreading concepts can seem difficult. This article explains processes and threads, uses a game analogy, and introduces three ways to create threads in Java.

Process: a runtime program encapsulation, the basic unit for OS resource scheduling and allocation, enabling concurrency.

Thread: a subtask of a process, the basic unit for CPU scheduling, enabling internal concurrency.

Analogy: a game match represents a process, while the chosen hero or in‑game monsters represent threads. A process can contain multiple threads, which is called multithreading.

Process and Thread

1. Threads run within a process. (A single hero or monster cannot run alone.)

2. Different processes do not affect each other; ending the main thread ends the whole process. (Two game matches are independent.)

3. Data sharing between processes is difficult. (Matches rarely share data.)

4. Threads within the same process share data easily. (All players' states are visible in one match.)

5. A process can limit its memory usage. (Room capacity limits the number of players.)

Three Ways to Create Threads

1) Extend the Thread class

Create a class that extends Thread and override run() :

public class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName() + ":打了" + i + "个小兵");
        }
    }
}

Test code:

MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
MyThread t3 = new MyThread();

t1.setName("鲁班");
t2.setName("刘备");
t3.setName("亚瑟");

t1.start();
t2.start();
t3.start();

2) Implement the Runnable interface

Create a class that implements Runnable and override run() :

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            try { Thread.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println(Thread.currentThread().getName() + "打了:" + i + "个小兵");
        }
    }
}

Test code:

MyRunnable mr = new MyRunnable();
Thread t1 = new Thread(mr, "张飞");
Thread t2 = new Thread(mr, "貂蝉");
Thread t3 = new Thread(mr, "吕布");

t1.start();
t2.start();
t3.start();

3) Implement the Callable interface

Implement Callable<String> to obtain a return value via FutureTask :

public class CallerTask implements Callable
{
    public String call() throws Exception {
        return "Hello,i am running!";
    }
    public static void main(String[] args) {
        FutureTask
task = new FutureTask<>(new CallerTask());
        new Thread(task).start();
        try {
            String result = task.get();
            System.out.println(result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

Common Thread Questions

1) Why override run() ?

The default run() does nothing; overriding provides the actual task for the thread.

2) Difference between run() and start() ?

run() : Executes the thread code like a normal method call.

start() : Starts a new thread; the JVM then invokes run() on that thread.

3) Extending Thread vs. implementing Runnable?

Implementing Runnable is preferred because it avoids Java's single‑inheritance limitation and separates task logic from thread control. Callable further allows a return value.

Other Thread Control Methods

1) sleep()

Pauses the current thread for a specified time. Must handle InterruptedException :

try {
    Thread.sleep(20);
} catch (InterruptedException e) {
    e.printStackTrace();
}

2) join()

Waits for a thread to finish before proceeding:

MyRunnable mr = new MyRunnable();
Thread t1 = new Thread(mr, "张飞");
Thread t2 = new Thread(mr, "貂蝉");
Thread t3 = new Thread(mr, "吕布");

t1.start();
try {
    t1.join(); // wait for t1 to finish
} catch (InterruptedException e) { e.printStackTrace(); }

t2.start();
t3.start();

3) setDaemon()

Marks a thread as a daemon (background) thread, such as the garbage‑collection thread:

MyRunnable mr = new MyRunnable();
Thread t1 = new Thread(mr, "张飞");
Thread t2 = new Thread(mr, "貂蝉");
Thread t3 = new Thread(mr, "吕布");

t1.setDaemon(true);
t2.setDaemon(true);

t1.start();
 t2.start();
 t3.start();

When all non‑daemon threads finish, the JVM exits and daemon threads stop automatically.

JavaconcurrencyThreadmultithreadingCallableRunnable
Java Tech Enthusiast
Written by

Java Tech Enthusiast

Sharing computer programming language knowledge, focusing on Java fundamentals, data structures, related tools, Spring Cloud, IntelliJ IDEA... Book giveaways, red‑packet rewards and other perks await!

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.