在 Java 中,线程是一种独立执行的程序单元,允许程序并发执行多个任务。Java 多线程编程是提高应用程序性能的常见手段,尤其在需要进行长时间计算、I/O 操作或并发处理任务时。Java 提供了多种线程管理方式,其中 传统线程技术 是最常见的编程方法之一。

1. 线程的基本概念

在计算机中,线程是进程中的一个执行单元。多个线程可以并行执行,从而提高程序的效率。每个线程都有自己的程序计数器、栈和局部变量,但与其他线程共享内存空间。

2. 创建线程的传统方法

在 Java 中,创建线程的方式主要有两种:

  1. 继承 Thread 类
  2. 实现 Runnable 接口

2.1 使用继承 Thread 类

Java 中的 Thread 类是一个表示线程的类,继承 Thread 类并重写它的 run() 方法来定义线程的任务。

步骤

  1. 创建一个新的类继承 Thread 类。
  2. 重写 run() 方法,定义线程的执行内容。
  3. 创建 Thread 类的对象,并调用 start() 方法启动线程。

示例代码

class MyThread extends Thread {
    @Override
    public void run() {
        // 线程任务
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + ": " + i);
            try {
                Thread.sleep(500);  // 让线程暂停 500 毫秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class ThreadExample {
    public static void main(String[] args) {
        MyThread thread1 = new MyThread();  // 创建线程
        MyThread thread2 = new MyThread();  // 创建线程
        
        thread1.start();  // 启动线程
        thread2.start();  // 启动线程
    }
}

解释

  • Thread.currentThread().getName() 获取当前线程的名称。
  • Thread.sleep(500) 让线程暂停 500 毫秒,模拟一些任务。
  • start() 方法是线程的启动方法,底层会调用 run() 方法执行线程任务。

2.2 使用实现 Runnable 接口

另一种方法是通过实现 Runnable 接口。Runnable 接口有一个方法 run(),它定义了线程的执行任务。

步骤

  1. 创建一个类实现 Runnable 接口。
  2. 重写 run() 方法,定义线程的任务。
  3. 使用 Thread 类将 Runnable 实例传递给线程,并启动线程。

示例代码

class MyRunnable implements Runnable {
    @Override
    public void run() {
        // 线程任务
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + ": " + i);
            try {
                Thread.sleep(500);  // 让线程暂停 500 毫秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class RunnableExample {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();  // 创建 Runnable 实现类实例
        Thread thread1 = new Thread(myRunnable);   // 创建线程对象
        Thread thread2 = new Thread(myRunnable);   // 创建线程对象
        
        thread1.start();  // 启动线程
        thread2.start();  // 启动线程
    }
}

解释

  • Runnable 接口通常用于当你需要多个线程共享相同的任务逻辑时。
  • 通过将 Runnable 对象传递给 Thread 构造函数来创建线程。

3. 线程的生命周期

Java 线程的生命周期通常包括以下几种状态:

  1. 新建(New):线程对象已创建,但尚未调用 start() 方法。
  2. 就绪(Runnable):线程调用了 start() 方法,等待 CPU 调度执行。
  3. 运行(Running):线程在 CPU 上执行,正在执行 run() 方法中的代码。
  4. 阻塞(Blocked):线程在等待某些资源时会进入阻塞状态,例如等待 I/O 操作完成或获取锁。
  5. 等待(Waiting):线程处于无限期等待状态,例如调用 wait()join() 或 sleep() 方法。
  6. 死亡(Dead):线程执行完毕或被强制终止。

4. 线程的控制方法

  • start(): 启动线程,调用线程的 run() 方法开始执行。
  • sleep(long millis): 暂停当前线程的执行指定的毫秒时间。
  • interrupt(): 中断线程的执行。
  • join(): 等待一个线程完成后再继续执行主线程。
  • yield(): 让当前线程暂停执行,给其他线程执行的机会。

5. 线程同步

多线程编程中,经常会遇到线程之间共享资源的情况,线程安全就显得尤为重要。为了避免多个线程同时访问共享资源,导致数据不一致的情况,Java 提供了同步机制。

5.1 同步方法

可以使用 synchronized 关键字来保证方法的同步性,使得同一时刻只有一个线程能够访问该方法。

示例代码

class Counter {
    private int count = 0;

    // 同步方法,保证线程安全
    public synchronized void increment() {
        count++;
    }

    public int getCount() {
        return count;
    }
}

public class SyncExample {
    public static void main(String[] args) {
        Counter counter = new Counter();

        // 创建多个线程对同一资源进行操作
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

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

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final count: " + counter.getCount());
    }
}

解释

  • synchronized 关键字保证了同一时刻只有一个线程能够执行 increment() 方法。
  • join() 方法确保主线程等待 t1 和 t2 线程执行完毕后再输出最终结果。

5.2 同步块

你可以将 synchronized 用于某些代码块,以便只对这部分代码进行同步,而不是整个方法。

示例代码

public class Counter {
    private int count = 0;

    public void increment() {
        synchronized (this) {  // 同步块
            count++;
        }
    }

    public int getCount() {
        return count;
    }
}

6. 线程池

虽然传统的线程技术使用 Thread 类和 Runnable 接口来创建线程,但在实际开发中,创建和销毁大量线程是非常低效的。Java 提供了 线程池 来优化线程管理,减少创建和销毁线程的开销。可以使用 ExecutorService 来管理线程池。

总结

  • Java 提供了两种传统的线程创建方式:继承 Thread 类和实现 Runnable 接口。
  • 线程有五种基本状态:新建、就绪、运行、阻塞、死亡。
  • 线程的同步是非常重要的,可以使用 synchronized 关键字来确保线程安全。
  • 为了提高性能和资源利用率,通常会使用 线程池 来管理线程。

如果你对多线程编程有更深的兴趣,或者需要了解其他多线程相关内容(如线程安全、线程池等),随时告诉我!