ZetCode

Java 线程类

最后修改时间:2025 年 4 月 13 日

java.lang.Thread 类是 Java 多线程能力的基础。它代表 Java 程序中的一个执行线程。线程允许并发执行代码段,从而实现高效的资源利用。

线程共享相同的内存空间,但独立执行。Thread 类提供了创建、控制和管理线程的方法。理解线程对于编写响应迅速且高效的 Java 应用程序至关重要。

线程类方法

Thread 类提供了控制线程执行和查询线程状态的方法。主要方法包括 startrunsleepjoininterrupt。这些方法管理线程生命周期和同步。

public class Thread implements Runnable {
    public Thread() {...}
    public Thread(Runnable target) {...}
    public void start() {...}
    public void run() {...}
    public static void sleep(long millis) throws InterruptedException {...}
    public final void join() throws InterruptedException {...}
    public void interrupt() {...}
    public static Thread currentThread() {...}
    public final boolean isAlive() {...}
    public final void setPriority(int priority) {...}
}

上面的代码展示了 Thread 类的关键方法。这些方法支持线程创建、执行控制和状态监控。可以通过扩展 Thread 或实现 Runnable 来创建线程。

通过扩展 Thread 类创建线程

创建线程的最简单方法是扩展 Thread 类并重写其 run 方法。start 方法启动线程执行。这种方法简单明了,但限制了继承。

Main.java
package com.zetcode;

class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("Thread running: " + i);
            try {
                Thread.sleep(500); // Pause for 500ms
            } catch (InterruptedException e) {
                System.out.println("Thread interrupted");
                return;
            }
        }
    }
}

void main() {
    MyThread thread = new MyThread();
    thread.start(); // Start the thread
    
    // Main thread continues execution
    for (int i = 0; i < 3; i++) {
        System.out.println("Main thread: " + i);
        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

此示例演示了通过扩展 Thread 创建线程。主线程和 MyThread 并发执行。输出显示交错执行。Thread.sleep 暂停执行,不消耗 CPU 资源。

通过实现 Runnable 创建线程

更灵活的方法是实现 Runnable 接口。这允许类在仍然可以作为线程执行的同时,扩展另一个类。Runnable 对象被传递给 Thread 构造函数。

Main.java
package com.zetcode;

class Task implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("Task executing: " + i);
            try {
                Thread.sleep(400);
            } catch (InterruptedException e) {
                System.out.println("Task interrupted");
                return;
            }
        }
    }
}

void main() {
    Task task = new Task();
    Thread thread = new Thread(task);
    thread.start();
    
    // Main thread work
    for (int i = 0; i < 4; i++) {
        System.out.println("Main thread working");
        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

此示例显示了使用 Runnable 创建线程。Task 类实现 Runnable 并在其 run 方法中定义工作。使用 Task 实例创建一个 Thread 对象。两种方法都实现了类似的结果,但 Runnable 更灵活。

线程休眠和中断

sleep 方法将线程执行暂停指定的时间。可以使用 interrupt 中断线程,该方法发送中断信号。正确的中断处理使线程更具响应性。

Main.java
package com.zetcode;

class Worker implements Runnable {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 10; i++) {
                System.out.println("Working... " + i);
                if (Thread.interrupted()) {
                    System.out.println("Thread was interrupted");
                    return;
                }
                Thread.sleep(500);
            }
        } catch (InterruptedException e) {
            System.out.println("Thread interrupted during sleep");
            return;
        }
    }
}

void main() throws InterruptedException {
    Thread worker = new Thread(new Worker());
    worker.start();
    
    Thread.sleep(2000); // Let worker run for 2 seconds
    worker.interrupt(); // Interrupt the worker
    worker.join(); // Wait for worker to finish
    System.out.println("Main thread done");
}

此示例演示了线程中断。Worker 使用 Thread.interrupted 检查中断并处理 InterruptedException。主线程在 2 秒后中断 Worker。正确的中断处理确保干净的线程终止。

线程加入

join 方法允许一个线程等待另一个线程完成。当线程执行顺序很重要或者需要合并结果时,这非常有用。Join 可以指定最大等待时间。

Main.java
package com.zetcode;

class Calculator implements Runnable {
    private int result;
    
    @Override
    public void run() {
        result = 0;
        for (int i = 1; i <= 100; i++) {
            result += i;
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                System.out.println("Calculation interrupted");
                return;
            }
        }
    }
    
    public int getResult() {
        return result;
    }
}

void main() throws InterruptedException {
    Calculator calc = new Calculator();
    Thread calcThread = new Thread(calc);
    calcThread.start();
    
    System.out.println("Waiting for calculation to complete...");
    calcThread.join(); // Wait for calculation to finish
    System.out.println("Result: " + calc.getResult());
}

此示例显示线程加入。主线程使用 join 等待 Calculator 完成。如果没有加入,main 可能会在计算完成之前访问结果。加入确保适当的同步。

线程优先级

线程优先级向调度程序提示线程的重要性。优先级范围从 1 (MIN_PRIORITY) 到 10 (MAX_PRIORITY)。默认值为 5 (NORM_PRIORITY)。优先级较高的线程获得更多的 CPU 时间,但不保证首先运行。

Main.java
package com.zetcode;

class Counter implements Runnable {
    private String name;
    
    public Counter(String name) {
        this.name = name;
    }
    
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(name + ": " + i);
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

void main() {
    Thread lowPriority = new Thread(new Counter("Low"));
    Thread highPriority = new Thread(new Counter("High"));
    
    lowPriority.setPriority(Thread.MIN_PRIORITY);
    highPriority.setPriority(Thread.MAX_PRIORITY);
    
    highPriority.start();
    lowPriority.start();
}

此示例演示了线程优先级。高优先级线程通常在低优先级线程之前执行,但这不能保证。线程调度取决于 JVM 和操作系统实现。

线程同步

线程同步防止并发访问共享资源。synchronized 关键字创建了每次只能由一个线程进入的临界区。这可以防止竞争条件和数据损坏。

Main.java
package com.zetcode;

class Counter {
    private int count = 0;
    
    public synchronized void increment() {
        count++;
    }
    
    public synchronized int getCount() {
        return count;
    }
}

class Incrementer implements Runnable {
    private Counter counter;
    
    public Incrementer(Counter counter) {
        this.counter = counter;
    }
    
    @Override
    public void run() {
        for (int i = 0; i < 10000; i++) {
            counter.increment();
        }
    }
}

void main() throws InterruptedException {
    Counter counter = new Counter();
    Thread t1 = new Thread(new Incrementer(counter));
    Thread t2 = new Thread(new Incrementer(counter));
    
    t1.start();
    t2.start();
    
    t1.join();
    t2.join();
    
    System.out.println("Final count: " + counter.getCount());
}

此示例显示线程同步。如果没有 synchronized 方法,由于竞争条件,最终计数可能小于 20000。同步确保对 count 变量的原子访问。结果始终为 20000。

来源

Java 线程类文档

本教程通过实际示例介绍了基本的 Thread 类概念。理解线程对于编写并发 Java 应用程序至关重要。正确的线程管理确保高效的资源利用和响应能力。

作者

我叫 Jan Bodnar,是一位敬业的程序员,在该领域拥有多年的经验。我于 2007 年开始撰写编程文章,此后撰写了 1,400 多篇文章和 8 本电子书。拥有超过八年的教学经验,我致力于分享我的知识并帮助他人掌握编程概念。

列出所有Java教程