教程中心 / Java教程 / 多线程基础

多线程基础

25分钟 高级特性

引言:什么是线程?

线程(Thread)是程序执行的最小单位。一个进程(程序)可以包含多个线程,这些线程同时执行,互不干扰。

进程 vs 线程类比

想象一家餐厅:
├── 进程 = 整个餐厅
└── 线程 = 餐厅里的员工

一个餐厅(进程)可以有多个员工(线程)同时工作:
- 一个员工在炒菜
- 一个员工在洗碗
- 一个员工在招待客人

他们共享餐厅的资源,但同时做不同的事情

为什么需要多线程?

  • 提高效率:多核CPU可以同时执行多个任务
  • 防止阻塞:一个任务阻塞时,其他任务继续执行
  • 提升性能:充分利用CPU空闲时间

线程的创建方式

方式1:继承Thread类

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("线程执行中: " + Thread.currentThread().getName());
    }
}

// 使用
MyThread thread = new MyThread();
thread.start();  // 启动线程(不是run()!)

方式2:实现Runnable接口(推荐)

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("线程执行中: " + Thread.currentThread().getName());
    }
}

// 使用
Thread thread = new Thread(new MyRunnable());
thread.start();

方式3:使用Lambda表达式(Java 8+)

// 最简洁的方式
Thread thread = new Thread(() -> {
    System.out.println("Lambda线程执行中!");
});
thread.start();

重要:启动线程必须调用start()方法,而不是run()方法。start()会创建新线程并执行run(),而run()只是普通方法调用,不会创建新线程。

线程的状态

线程在生命周期中会经历不同的状态:

状态说明
NEW新建状态,线程刚创建但未启动
RUNNABLE可运行状态,正在Java虚拟机中执行或等待CPU
BLOCKED阻塞状态,等待获取锁
WAITING等待状态,无限期等待另一个线程
TIMED_WAITING计时等待状态,在指定时间后自动唤醒
TERMINATED终止状态,线程执行完毕

获取线程状态

Thread thread = new Thread(() -> {
    System.out.println("执行中...");
});

System.out.println(thread.getState());  // NEW
thread.start();
System.out.println(thread.getState());  // RUNNABLE

线程的常用方法

方法说明
start()启动线程
run()线程执行的内容
sleep(ms)让线程休眠指定毫秒
join()等待线程执行完毕
yield()让出CPU时间片
interrupt()中断线程
getName()获取线程名称
getState()获取线程状态
currentThread()获取当前线程对象

sleep() - 线程休眠

Thread thread = new Thread(() -> {
    System.out.println("线程开始执行");
    try {
        Thread.sleep(2000);  // 休眠2秒
        System.out.println("线程2秒后继续执行");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});
thread.start();

join() - 等待线程结束

Thread thread = new Thread(() -> {
    System.out.println("子线程开始");
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {}
    System.out.println("子线程结束");
});

thread.start();
thread.join();  // 等待thread执行完毕
System.out.println("主线程继续执行");

线程同步

当多个线程访问共享资源时,需要进行同步控制,否则可能导致数据不一致。

问题演示:多线程抢票

class TicketSeller implements Runnable {
    private int tickets = 10;  // 共享资源

    @Override
    public void run() {
        while (tickets > 0) {
            System.out.println(Thread.currentThread().getName() + "卖出第" + tickets + "张票");
            tickets--;
            try {
                Thread.sleep(100);  // 模拟网络延迟
            } catch (InterruptedException e) {}
        }
    }
}

// 问题:多个线程可能卖出同一张票!
TicketSeller seller = new TicketSeller();
new Thread(seller, "窗口1").start();
new Thread(seller, "窗口2").start();
new Thread(seller, "窗口3").start();

synchronized - 同步方法

class TicketSeller implements Runnable {
    private int tickets = 10;

    @Override
    public synchronized void run() {  // 同步方法
        while (tickets > 0) {
            System.out.println(Thread.currentThread().getName() + "卖出第" + tickets + "张票");
            tickets--;
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {}
        }
    }
}

synchronized - 同步代码块

class TicketSeller implements Runnable {
    private int tickets = 10;
    private Object lock = new Object();  // 锁对象

    @Override
    public void run() {
        while (true) {
            synchronized (lock) {  // 同步代码块
                if (tickets > 0) {
                    System.out.println(Thread.currentThread().getName() + "卖出第" + tickets + "张票");
                    tickets--;
                } else {
                    break;
                }
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {}
        }
    }
}

synchronized原理:每个对象都有一把锁(称为监视器锁)。当线程进入synchronized代码块时,必须获取该对象的锁,执行完毕后自动释放锁。

线程安全的类

Java提供了一些线程安全的类,可以在多线程环境下直接使用:

线程不安全的类线程安全的替代
ArrayListVector、CopyOnWriteArrayList
HashMapConcurrentHashMap
StringBuilderStringBuffer

StringBuffer线程安全示例

// StringBuffer是线程安全的,所有方法都用synchronized修饰
StringBuffer sb = new StringBuffer();
sb.append("Hello");
sb.append(" World");
System.out.println(sb.toString());

volatile关键字

volatile保证变量的可见性,即一个线程修改了volatile变量的值,其他线程能立即看到。

class VolatileDemo extends Thread {
    private volatile boolean running = true;  // volatile保证可见性

    @Override
    public void run() {
        while (running) {
            System.out.println("线程运行中...");
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {}
        }
        System.out.println("线程停止");
    }

    public void stopThread() {
        running = false;  // 主线程修改,子线程立即看到
    }
}

小结

  • 线程是程序执行的最小单位,提高程序效率
  • 创建线程的方式:继承Thread实现Runnable(推荐)
  • 启动线程调用start(),不是run()
  • synchronized实现线程同步,保证共享资源安全
  • 线程状态:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED
  • volatile保证变量可见性
☕ Java 在线代码编辑器
📝 运行结果