Java多线程

一、多线程基础概念

1. 什么是线程?

线程是程序中执行的最小单位,一个进程可以包含多个线程。例如,浏览器可以同时下载文件、播放视频和渲染页面,这些都是通过不同线程实现的。

2. 为什么需要多线程?
  • 提高 CPU 利用率:当一个线程等待 IO 操作时,其他线程可以继续执行。
  • 改善响应性:例如 GUI 应用中,主线程负责界面响应,后台线程处理耗时任务。
  • 充分利用多核 CPU:现代处理器通常有多核,多线程可以并行执行在不同核心上。

二、Java 中创建线程的方式

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

    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start(); // 启动线程,JVM会调用run()方法
        System.out.println("主线程: " + Thread.currentThread().getName());
    }
}
2. 实现 Runnable 接口
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("线程执行中: " + Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable());
        thread.start();
        System.out.println("主线程: " + Thread.currentThread().getName());
    }
}
3. 实现 Callable 接口(带返回值)
import java.util.concurrent.*;

public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        Thread.sleep(1000);
        return "任务执行完成: " + Thread.currentThread().getName();
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<String> future = executor.submit(new MyCallable());
        System.out.println(future.get()); // 获取返回值,会阻塞直到任务完成
        executor.shutdown();
    }
}

三、线程的生命周期

Java 线程有 6 种状态,定义在Thread.State枚举中:

  1. NEW:线程刚被创建,但还未调用start()方法。
  2. RUNNABLE:线程正在 Java 虚拟机中执行,或者准备执行(等待 CPU 时间片)。
  3. BLOCKED:线程被阻塞,等待获取监视器锁(例如进入synchronized块 / 方法)。
  4. WAITING:线程无限期等待另一个线程执行特定操作(例如调用wait()join())。
  5. TIMED_WAITING:线程在指定时间内等待(例如调用Thread.sleep(1000))。
  6. TERMINATED:线程执行完毕或因异常终止。

四、线程同步与锁

1. synchronized 关键字

用于实现线程同步,确保同一时间只有一个线程可以执行被保护的代码块或方法。

public class Counter {
    private int count = 0;

    // 同步方法
    public synchronized void increment() {
        count++;
    }

    // 同步代码块
    public void decrement() {
        synchronized (this) {
            count--;
        }
    }
}
2. ReentrantLock

java.util.concurrent.locks包中的显式锁,功能比synchronized更强大。

import java.util.concurrent.locks.ReentrantLock;

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

    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock(); // 必须在finally中释放锁
        }
    }
}
3. 原子操作类

java.util.concurrent.atomic包提供了原子操作类,基于 CAS(Compare-and-Swap)实现无锁并发。

import java.util.concurrent.atomic.AtomicInteger;

public class Counter {
    private AtomicInteger count = new AtomicInteger(0);

    public void increment() {
        count.incrementAndGet(); // 原子操作
    }
}

五、线程间通信

1. wait()、notify()、notifyAll()

这些方法是 Object 类的一部分,用于线程间协作。

public class ProducerConsumer {
    private static final Object lock = new Object();
    private static boolean ready = false;

    public static void main(String[] args) {
        // 生产者线程
        new Thread(() -> {
            synchronized (lock) {
                System.out.println("生产者准备数据...");
                ready = true;
                lock.notify(); // 通知等待的线程
            }
        }).start();

        // 消费者线程
        new Thread(() -> {
            synchronized (lock) {
                while (!ready) {
                    try {
                        lock.wait(); // 等待数据准备好
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
                System.out.println("消费者处理数据");
            }
        }).start();
    }
}
2. Condition 接口

ReentrantLock的高级替代方案,提供更灵活的等待 / 通知机制。

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

public class ProducerConsumer {
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();
    private boolean ready = false;

    public void produce() {
        lock.lock();
        try {
            System.out.println("生产者准备数据...");
            ready = true;
            condition.signal(); // 唤醒等待的线程
        } finally {
            lock.unlock();
        }
    }

    public void consume() {
        lock.lock();
        try {
            while (!ready) {
                condition.await(); // 等待数据准备好
            }
            System.out.println("消费者处理数据");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();
        }
    }
}

六、高级主题

1. 线程池(Executor 框架)

线程池管理一组工作线程,避免频繁创建和销毁线程的开销。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolExample {
    public static void main(String[] args) {
        // 创建固定大小的线程池
        ExecutorService executor = Executors.newFixedThreadPool(5);

        // 提交任务
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            executor.submit(() -> {
                System.out.println("执行任务: " + taskId + " 线程: " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }

        // 关闭线程池
        executor.shutdown();
    }
}
2. 并发集合类

java.util.concurrent包提供了多种线程安全的集合类:

  • ConcurrentHashMap:高效的线程安全哈希表
  • CopyOnWriteArrayList:写时复制的列表,适合读多写少的场景
  • BlockingQueue:阻塞队列,常用于生产者 - 消费者模式
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class BlockingQueueExample {
    public static void main(String[] args) {
        BlockingQueue<String> queue = new LinkedBlockingQueue<>(10);

        // 生产者线程
        new Thread(() -> {
            try {
                queue.put("数据1");
                queue.put("数据2");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();

        // 消费者线程
        new Thread(() -> {
            try {
                System.out.println("消费: " + queue.take());
                System.out.println("消费: " + queue.take());
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();
    }
}
3. Future 和 CompletableFuture

用于异步计算和处理结果。

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CompletableFutureExample {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创建异步任务
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            return "异步任务结果";
        });

        // 任务完成后执行回调
        future.thenAccept(result -> System.out.println("处理结果: " + result));

        // 阻塞等待结果
        System.out.println(future.get());
    }
}
4. 原子变量与 CAS

AtomicIntegerAtomicLong等原子类基于 CAS 实现无锁并发。

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicExample {
    private static AtomicInteger counter = new AtomicInteger(0);

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.incrementAndGet();
            }
        });

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

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

        System.out.println("计数器值: " + counter.get()); // 输出2000,无竞争问题
    }
}

七、线程安全实践建议

  1. 不可变对象:优先使用不可变对象(如StringInteger),它们天生线程安全。
  2. 最小化共享状态:尽量减少多线程共享的变量和资源。
  3. 使用线程安全类:优先使用java.util.concurrent包中的类,而非自己实现同步。
  4. 避免死锁
    • 按固定顺序获取锁
    • 使用带超时的锁获取方法(如tryLock
  5. 正确处理中断:在线程中正确响应interrupt()请求,避免资源泄漏。

八、性能调优与监控

  1. 线程池大小优化

    • CPU 密集型任务:线程数 = CPU 核心数 + 1
    • IO 密集型任务:线程数 = CPU 核心数 × (1 + 平均等待时间 / 平均处理时间)
  2. 工具与监控

    • jstack:打印线程堆栈信息,用于分析死锁和阻塞问题
    • VisualVM:可视化监控工具,查看线程状态、CPU 使用率等
    • ThreadMXBean:Java 代码中获取线程信息的 API
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;

public class ThreadMonitor {
    public static void main(String[] args) {
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        long[] threadIds = threadMXBean.getAllThreadIds();
        ThreadInfo[] threadInfos = threadMXBean.getThreadInfo(threadIds, 10);

        for (ThreadInfo info : threadInfos) {
            System.out.println("线程: " + info.getThreadName() + " 状态: " + info.getThreadState());
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值