Java多线程基本介绍

一、多线程基础概念

1.1 进程与线程的区别

进程是操作系统资源分配的基本单位,具有独立的内存空间和系统资源。线程是CPU调度的基本单位,是进程中的一个执行路径,共享进程的内存和资源。

主要区别:

  • 进程间相互独立,线程共享进程资源

  • 进程切换开销大,线程切换开销小

  • 进程通信复杂(IPC),线程通信简单(共享内存)

  • 进程更安全(隔离),线程更高效

1.2 为什么需要多线程

  1. 提高CPU利用率:当线程因I/O操作阻塞时,其他线程可以继续执行

  2. 提高响应性:GUI应用使用多线程保持界面响应

  3. 简化建模:某些问题(如仿真)更适合用多线程表达

  4. 充分利用多核CPU:现代CPU多为多核,多线程可以并行执行

1.3 Java线程实现方式

1.3.1 继承Thread类
class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("Thread running: " + Thread.currentThread().getName());
    }
}

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

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

public static void main(String[] args) {
    Thread thread = new Thread(new MyRunnable());
    thread.start();
}
1.3.3 实现Callable接口(带返回值)
class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        return "Callable result: " + Thread.currentThread().getName();
    }
}

public static void main(String[] args) throws Exception {
    FutureTask<String> futureTask = new FutureTask<>(new MyCallable());
    Thread thread = new Thread(futureTask);
    thread.start();
    System.out.println(futureTask.get()); // 获取返回值
}
1.3.4 Lambda表达式(Java8+)
public static void main(String[] args) {
    // Runnable
    new Thread(() -> System.out.println("Lambda thread running")).start();
    
    // Callable
    FutureTask<String> futureTask = new FutureTask<>(() -> "Lambda callable");
    new Thread(futureTask).start();
}

二、线程生命周期与状态转换

2.1 线程的6种状态(Java Thread.State)

  1. NEW:新建但未启动

  2. RUNNABLE:可运行(包括就绪和运行中)

  3. BLOCKED:等待监视器锁(synchronized)

  4. WAITING:无限期等待(wait()/join()/park())

  5. TIMED_WAITING:有限期等待(sleep()/wait(n)/join(n))

  6. TERMINATED:终止

2.2 状态转换图

NEW --start()--> RUNNABLE
RUNNABLE --获取锁--> 运行中
RUNNABLE --未获取锁--> BLOCKED
RUNNABLE --wait()/join()--> WAITING
RUNNABLE --sleep(n)/wait(n)/join(n)--> TIMED_WAITING
WAITING/TIMED_WAITING --notify()/notifyAll()/unpark()/超时--> RUNNABLE
任何状态 --异常/完成--> TERMINATED

2.3 状态检查与控制方法

Thread thread = new Thread(() -> {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});

System.out.println(thread.getState()); // NEW
thread.start();
System.out.println(thread.getState()); // RUNNABLE
Thread.sleep(100);
System.out.println(thread.getState()); // TIMED_WAITING
thread.join();
System.out.println(thread.getState()); // TERMINATED

三、线程同步与锁机制

3.1 同步问题示例:银行转账

j

class BankAccount {
    private int balance;
    
    public BankAccount(int balance) {
        this.balance = balance;
    }
    
    // 非同步方法会导致并发问题
    public void transfer(BankAccount dest, int amount) {
        this.balance -= amount;
        dest.balance += amount;
    }
}

3.2 synchronized关键字

3.2.1 同步方法
public synchronized void transfer(BankAccount dest, int amount) {
    this.balance -= amount;
    dest.balance += amount;
}
3.2.2 同步代码块
public void transfer(BankAccount dest, int amount) {
    synchronized(this) {
        this.balance -= amount;
        synchronized(dest) {
            dest.balance += amount;
        }
    }
}

3.3 volatile关键字

保证变量的可见性(但不保证原子性):

class SharedObject {
    private volatile boolean flag = false;
    
    public void setFlag() {
        flag = true;
    }
    
    public void doWork() {
        while(!flag) {
            // 循环直到flag变为true
        }
    }
}

3.4 Java并发包中的锁

3.4.1 ReentrantLock
class Counter {
    private final Lock lock = new ReentrantLock();
    private int count = 0;
    
    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }
}
3.4.2 ReadWriteLock
class DataCache {
    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    private Map<String, Object> cache = new HashMap<>();
    
    public Object get(String key) {
        rwLock.readLock().lock();
        try {
            return cache.get(key);
        } finally {
            rwLock.readLock().unlock();
        }
    }
    
    public void put(String key, Object value) {
        rwLock.writeLock().lock();
        try {
            cache.put(key, value);
        } finally {
            rwLock.writeLock().unlock();
        }
    }
}

四、线程间通信

4.1 wait()/notify()机制

class MessageQueue {
    private Queue<String> queue = new LinkedList<>();
    private int maxSize;
    
    public MessageQueue(int maxSize) {
        this.maxSize = maxSize;
    }
    
    public synchronized void put(String message) throws InterruptedException {
        while(queue.size() == maxSize) {
            wait(); // 队列满时等待
        }
        queue.add(message);
        notifyAll(); // 通知消费者
    }
    
    public synchronized String take() throws InterruptedException {
        while(queue.isEmpty()) {
            wait(); // 队列空时等待
        }
        String message = queue.remove();
        notifyAll(); // 通知生产者
        return message;
    }
}

4.2 Condition条件变量

class BoundedBuffer {
    final Lock lock = new ReentrantLock();
    final Condition notFull = lock.newCondition();
    final Condition notEmpty = lock.newCondition();
    final Object[] items = new Object[100];
    int putptr, takeptr, count;
    
    public void put(Object x) throws InterruptedException {
        lock.lock();
        try {
            while(count == items.length)
                notFull.await();
            items[putptr] = x;
            if(++putptr == items.length) putptr = 0;
            ++count;
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }
    
    public Object take() throws InterruptedException {
        lock.lock();
        try {
            while(count == 0)
                notEmpty.await();
            Object x = items[takeptr];
            if(++takeptr == items.length) takeptr = 0;
            --count;
            notFull.signal();
            return x;
        } finally {
            lock.unlock();
        }
    }
}

五、Java并发工具类

5.1 CountDownLatch

public class WorkerService {
    public static void main(String[] args) throws InterruptedException {
        int workerCount = 5;
        CountDownLatch startSignal = new CountDownLatch(1);
        CountDownLatch doneSignal = new CountDownLatch(workerCount);
        
        for(int i = 0; i < workerCount; i++) {
            new Thread(new Worker(startSignal, doneSignal, "Worker-"+i)).start();
        }
        
        System.out.println("准备工作...");
        Thread.sleep(1000); // 模拟准备工作
        System.out.println("开始工作!");
        startSignal.countDown(); // 所有worker开始工作
        
        doneSignal.await(); // 等待所有worker完成
        System.out.println("所有工作完成!");
    }
    
    static class Worker implements Runnable {
        private final CountDownLatch startSignal;
        private final CountDownLatch doneSignal;
        private final String name;
        
        Worker(CountDownLatch startSignal, CountDownLatch doneSignal, String name) {
            this.startSignal = startSignal;
            this.doneSignal = doneSignal;
            this.name = name;
        }
        
        public void run() {
            try {
                startSignal.await(); // 等待开始信号
                System.out.println(name + " 正在工作...");
                Thread.sleep((long)(Math.random() * 1000)); // 模拟工作
                System.out.println(name + " 工作完成");
                doneSignal.countDown();
            } catch(InterruptedException ex) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

5.2 CyclicBarrier

public class MeetingPoint {
    public static void main(String[] args) {
        int threadCount = 3;
        CyclicBarrier barrier = new CyclicBarrier(threadCount, () -> 
            System.out.println("所有线程已到达屏障点,继续执行"));
        
        for(int i = 0; i < threadCount; i++) {
            new Thread(new Task(barrier), "Thread-"+i).start();
        }
    }
    
    static class Task implements Runnable {
        private final CyclicBarrier barrier;
        
        Task(CyclicBarrier barrier) {
            this.barrier = barrier;
        }
        
        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread().getName() + " 开始第一阶段工作");
                Thread.sleep((long)(Math.random() * 2000));
                System.out.println(Thread.currentThread().getName() + " 到达屏障点");
                barrier.await();
                
                System.out.println(Thread.currentThread().getName() + " 开始第二阶段工作");
                Thread.sleep((long)(Math.random() * 2000));
                System.out.println(Thread.currentThread().getName() + " 到达屏障点");
                barrier.await();
                
                System.out.println(Thread.currentThread().getName() + " 完成所有工作");
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    }
}

5.3 Semaphore

public class ConnectionPool {
    private static final int MAX_AVAILABLE = 10;
    private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
    private final Set<Connection> connections = new HashSet<>();
    
    public ConnectionPool() {
        for(int i = 0; i < MAX_AVAILABLE; i++) {
            connections.add(new MockConnection());
        }
    }
    
    public Connection getConnection() throws InterruptedException {
        available.acquire();
        return getNextAvailableConnection();
    }
    
    public void releaseConnection(Connection c) {
        if(markAsUnused(c)) {
            available.release();
        }
    }
    
    private synchronized Connection getNextAvailableConnection() {
        for(Connection c : connections) {
            if(!c.isInUse()) {
                c.markInUse();
                return c;
            }
        }
        return null;
    }
    
    private synchronized boolean markAsUnused(Connection c) {
        if(c.isInUse()) {
            c.markUnused();
            return true;
        }
        return false;
    }
    
    interface Connection {
        void markInUse();
        void markUnused();
        boolean isInUse();
    }
    
    class MockConnection implements Connection {
        private volatile boolean inUse = false;
        
        public void markInUse() { inUse = true; }
        public void markUnused() { inUse = false; }
        public boolean isInUse() { return inUse; }
    }
}

六、线程池与Executor框架

6.1 线程池的优势

  1. 降低资源消耗:重复利用已创建的线程

  2. 提高响应速度:任务到达时线程已存在

  3. 提高线程可管理性:统一分配、调优和监控

  4. 提供更多功能:定时执行、定期执行等

6.2 ThreadPoolExecutor

public class ThreadPoolDemo {
    public static void main(String[] args) {
        int corePoolSize = 5;
        int maxPoolSize = 10;
        long keepAliveTime = 5000;
        
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
            corePoolSize,              // 核心线程数
            maxPoolSize,               // 最大线程数
            keepAliveTime,             // 空闲线程存活时间
            TimeUnit.MILLISECONDS,     // 时间单位
            new LinkedBlockingQueue<Runnable>(100), // 工作队列
            new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
        );
        
        for(int i = 0; i < 20; i++) {
            executor.execute(new Task("Task-"+i));
        }
        
        executor.shutdown();
    }
    
    static class Task implements Runnable {
        private final String name;
        
        Task(String name) {
            this.name = name;
        }
        
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + " 执行 " + name);
            try {
                Thread.sleep(1000);
            } catch(InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

6.3 Executors工厂类

// 固定大小线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);

// 单线程池
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

// 可缓存线程池
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

// 定时任务线程池
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);

// 工作窃取线程池(Java8+)
ExecutorService workStealingPool = Executors.newWorkStealingPool();

6.4 Fork/Join框架

public class FibonacciTask extends RecursiveTask<Long> {
    private final long n;
    
    FibonacciTask(long n) {
        this.n = n;
    }
    
    @Override
    protected Long compute() {
        if(n <= 1) {
            return n;
        }
        FibonacciTask f1 = new FibonacciTask(n - 1);
        f1.fork(); // 异步执行
        
        FibonacciTask f2 = new FibonacciTask(n - 2);
        return f2.compute() + f1.join(); // 等待结果
    }
    
    public static void main(String[] args) {
        ForkJoinPool pool = new ForkJoinPool();
        FibonacciTask task = new FibonacciTask(10);
        System.out.println(pool.invoke(task)); // 输出55
    }
}

七、并发集合与原子类

7.1 并发集合类

7.1.1 ConcurrentHashMap
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("a", 1);
map.putIfAbsent("a", 2); // 不会替换已有值

// 原子更新
map.compute("a", (k, v) -> v == null ? 1 : v + 1);

// 搜索
Integer result = map.search(1, (k, v) -> v > 0 ? k : null);
7.1.2 CopyOnWriteArrayList
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("a");
list.addIfAbsent("a"); // 不会添加重复元素

// 迭代期间安全修改
for(String s : list) {
    list.add("new"); // 不会抛出ConcurrentModificationException
}

7.2 阻塞队列

7.2.1 ArrayBlockingQueue
BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
queue.put("item"); // 阻塞直到有空间
String item = queue.take(); // 阻塞直到有元素
7.2.2 LinkedBlockingQueue
BlockingQueue<String> queue = new LinkedBlockingQueue<>();
queue.offer("item", 1, TimeUnit.SECONDS); // 限时等待
String item = queue.poll(1, TimeUnit.SECONDS);

7.3 原子类

7.3.1 AtomicInteger
AtomicInteger counter = new AtomicInteger(0);
counter.incrementAndGet(); // 原子自增
counter.compareAndSet(1, 2); // CAS操作
7.3.2 LongAdder(高并发场景更优)
LongAdder adder = new LongAdder();
adder.increment();
adder.add(5);
long sum = adder.sum(); // 获取总和

八、Java内存模型与线程安全

8.1 Java内存模型(JMM)

  1. 主内存:所有变量存储的位置

  2. 工作内存:每个线程有自己的工作内存,保存主内存变量的副本

  3. 内存间交互操作

    • lock(锁定)

    • unlock(解锁)

    • read(读取)

    • load(载入)

    • use(使用)

    • assign(赋值)

    • store(存储)

    • write(写入)

8.2 happens-before原则

  1. 程序顺序规则:同一线程中的操作,前面的happens-before后面的

  2. 监视器锁规则:解锁happens-before后续加锁

  3. volatile变量规则:写happens-before后续读

  4. 线程启动规则:start()happens-before线程中的任何操作

  5. 线程终止规则:线程中的所有操作happens-before它的终止检测

  6. 中断规则:对线程interrupt()的调用happens-before被中断线程的代码检测到中断

  7. 终结器规则:对象的构造函数happens-before它的finalize()方法

  8. 传递性:A happens-before B,B happens-before C,则A happens-before C

8.3 线程安全实现方法

  1. 不可变对象:String、Integer等

  2. 互斥同步:synchronized、ReentrantLock

  3. 非阻塞同步:CAS操作(Atomic类)

  4. 无同步方案:ThreadLocal、栈封闭

九、常见多线程问题与解决方案

9.1 死锁与避免

死锁示例:

Object lock1 = new Object();
Object lock2 = new Object();

new Thread(() -> {
    synchronized(lock1) {
        try { Thread.sleep(100); } catch(Exception e) {}
        synchronized(lock2) {
            System.out.println("Thread1 got both locks");
        }
    }
}).start();

new Thread(() -> {
    synchronized(lock2) {
        try { Thread.sleep(100); } catch(Exception e) {}
        synchronized(lock1) {
            System.out.println("Thread2 got both locks");
        }
    }
}).start();

避免死锁策略:

  1. 按固定顺序获取锁

  2. 使用tryLock()设置超时

  3. 使用死锁检测工具

9.2 线程泄漏

原因:

  • 线程未正确关闭

  • 线程池未正确shutdown

解决方案:

ExecutorService executor = Executors.newFixedThreadPool(5);
try {
    // 提交任务
    executor.submit(() -> {...});
} finally {
    executor.shutdown(); // 或shutdownNow()
    if(!executor.awaitTermination(60, TimeUnit.SECONDS)) {
        executor.shutdownNow();
    }
}

9.3 上下文切换开销

优化建议:

  1. 减少锁竞争(缩小同步范围、使用读写锁)

  2. 使用无锁数据结构(ConcurrentHashMap、Atomic类)

  3. 合理设置线程池大小(CPU密集型:CPU核数+1;IO密集型:2*CPU核数)

十、Java多线程最佳实践

  1. 命名线程:方便调试和日志追踪

    java

    复制

    下载

    ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
        .setNameFormat("worker-%d").build();
    ExecutorService executor = Executors.newFixedThreadPool(5, namedThreadFactory);
  2. 优先使用并发工具类:而不是自己实现同步机制

  3. 处理中断:正确响应中断

    public void run() {
        try {
            while(!Thread.currentThread().isInterrupted()) {
                // 工作代码
            }
        } catch(InterruptedException e) {
            Thread.currentThread().interrupt(); // 恢复中断状态
        }
    }
  4. 避免过度同步:缩小同步范围,使用并发集合

  5. 使用ThreadLocal谨慎:防止内存泄漏

    try {
        ThreadLocal<Object> threadLocal = new ThreadLocal<>();
        threadLocal.set(new Object());
        // 使用threadLocal
    } finally {
        threadLocal.remove(); // 必须清理
    }
  6. 考虑使用CompletableFuture(Java8+)

    CompletableFuture.supplyAsync(() -> "Hello")
        .thenApply(s -> s + " World")
        .thenAccept(System.out::println);

总结

Java多线程编程是Java开发中的核心技能,掌握多线程技术可以:

  • 提高程序性能

  • 改善用户体验

  • 更好地利用硬件资源

但同时也带来复杂性:

  • 线程安全问题

  • 死锁风险

  • 性能调优挑战

建议开发者在实际项目中:

  1. 优先使用高级并发工具(如线程池、并发集合)

  2. 编写线程安全的代码

  3. 进行充分的并发测试

  4. 使用性能分析工具(如JProfiler、VisualVM)调优

随着Java版本更新,多线程API也在不断改进(如Java8的CompletableFuture、Java9的Flow API等),开发者应持续学习新的并发编程模式和技术。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值