Java多线程编程:从零到一的超详细教程

引言

在多核处理器日益普及的今天,充分利用多核资源提升程序性能已成为软件开发的重要方向。Java多线程编程作为实现并发和并行处理的核心技术,对于提高程序运行效率、优化资源利用具有重要意义。本教程旨在从零开始,全面、系统地讲解Java多线程编程的各个方面,包括线程基础、同步机制、并发工具、性能优化等内容,帮助读者掌握多线程编程的核心技能。

一、线程基础

1.1 线程的概念

线程是操作系统能够进行运算调度的最小单位,是进程中的一条执行路径。一个进程可以包含多个线程,这些线程共享进程的资源,如内存空间和文件句柄,但拥有各自独立的栈空间和程序计数器。

1.2 线程的创建

在Java中,创建线程主要有两种方式:继承Thread类和实现Runnable接口。

1.2.1 继承Thread

通过继承Thread类并重写run()方法,可以创建一个线程。

public class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("线程运行中");
    }

    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start(); // 启动线程
    }
}
1.2.2 实现Runnable接口

实现Runnable接口并传入Thread类的构造函数,也是创建线程的常见方式。这种方式更灵活,因为Java不支持多重继承,但可以实现多个接口。

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("线程运行中");
    }

    public static void main(String[] args) {
        MyRunnable runnable = new MyRunnable();
        Thread thread = new Thread(runnable);
        thread.start();
    }
}

线1.3 线程的生命周期

线程的生命周期包括以下几个阶段:

  1. 新建(New):线程对象被创建,但尚未启动。
  2. 就绪(Runnable):线程已经启动,正在等待获取CPU资源。
  3. 运行(Running):线程获得了CPU资源,正在执行。
  4. 阻塞(Blocked):线程由于某种原因(如等待I/O操作完成)暂停执行。
  5. 死亡(Dead):线程执行完毕或由于异常退出。

1.4 线程的启动与终止

1.4.1 启动线程

通过调用Thread对象的start()方法启动线程。start()方法会调用线程的run()方法,使线程进入就绪状态。

1.4.2 终止线程

线程在执行完run()方法后会自动终止。如果需要提前终止线程,可以通过设置标志位或使用interrupt()方法。

public class MyThread extends Thread {
    private volatile boolean running = true;

    @Override
    public void run() {
        while (running) {
            // 执行任务
        }
    }

    public void stopThread() {
        running = false;
    }
}

使用interrupt()方法:

public class MyThread extends Thread {
    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            // 执行任务
        }
    }
}

// 在另一个线程中调用interrupt()
thread.interrupt();

1.5 线程的优先级

Java线程可以设置优先级,优先级高的线程在竞争CPU资源时可能获得更多机会。优先级范围从1到10,默认优先级为5。

Thread thread = new Thread(runnable);
thread.setPriority(Thread.MAX_PRIORITY); // 设置最高优先级

1.6 线程的休眠与唤醒

1.6.1 休眠线程

通过Thread.sleep(long millis)方法可以使线程休眠指定的毫秒数。

try {
    Thread.sleep(1000); // 休眠1秒
} catch (InterruptedException e) {
    e.printStackTrace();
}
1.6.2 唤醒线程

sleep()方法会使线程进入阻塞状态,当休眠时间结束后,线程会自动唤醒。也可以通过interrupt()方法唤醒休眠中的线程,此时会抛出InterruptedException

1.7 线程的让步

Thread.yield()方法可以使当前线程主动让出CPU资源,让其他线程有机会执行。但yield()方法只是提示调度器,并不保证线程一定会让出CPU。

Thread.yield();

1.8 线程的合并

Thread.join()方法可以使当前线程等待另一个线程执行完毕后再继续执行。

Thread thread = new Thread(runnable);
thread.start();
try {
    thread.join(); // 等待thread执行完毕
} catch (InterruptedException e) {
    e.printStackTrace();
}

二、线程同步与通信

在多线程环境中,多个线程可能同时访问共享资源,导致数据不一致等问题。线程同步与通信机制用于解决这些问题,确保线程安全。

2.1 同步方法

使用synchronized关键字修饰方法,可以保证同一时间只有一个线程执行该方法。

public class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }
}

2.2 同步代码块

使用synchronized关键字修饰代码块,可以指定锁对象,实现更细粒度的同步。

public class Counter {
    private int count = 0;
    private final Object lock = new Object();

    public void increment() {
        synchronized (lock) {
            count++;
        }
    }

    public int getCount() {
        synchronized (lock) {
            return count;
        }
    }
}

2.3 锁对象

Java提供了Lock接口及其实现类ReentrantLock,提供更灵活的锁机制。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Counter {
    private int count = 0;
    private final Lock lock = new ReentrantLock();

    public void increment() {