JAVA-多线程

Java 多线程是 Java 编程中实现并发的重要特性,允许程序同时执行多个任务。Java 多线程通过 java.lang.Thread 类和 java.util.concurrent 包实现。线程是程序执行的最小单位,多线程允许程序同时执行多个任务。

1.多线程基础概念

多线程指一个进程中存在多个并发执行的线程,共享进程资源(内存、文件等),每个线程拥有独立的栈空间。优势包括:

1.1 线程与进程的区别

进程(Process)

  • 操作系统资源分配的基本单位

  • 拥有独立的地址空间

  • 进程间通信(IPC)成本高(管道、消息队列、共享内存等)

  • 创建和销毁开销大

线程(Thread)

  • CPU调度的基本单位

  • 共享进程的地址空间和资源

  • 线程间通信成本低(共享内存)

  • 创建和销毁开销小

类比解释

  • 进程就像一家公司,拥有独立的办公空间和资源

  • 线程就像公司里的员工,共享办公空间但各自独立工作

1.2 为什么需要多线程?

  1. 提高CPU利用率

    • 单线程在IO操作时CPU处于等待状态

    • 多线程可以在一个线程等待时运行其他线程

  2. 提升吞吐量

    • Web服务器可以同时处理多个请求

    • 数据库系统可以并行执行查询

  3. 改善响应时间

    • GUI程序主线程保持响应

    • 后台线程处理耗时任务

  4. 利用多核CPU

    • 现代CPU都是多核架构

    • 单线程无法充分利用硬件资源

1.3 多线程的挑战

  1. 线程安全问题

    • 竞态条件(Race Condition)

    • 数据竞争(Data Race)

  2. 死锁问题

    • 多个线程互相等待对方释放锁

  3. 性能问题

    • 上下文切换开销

    • 锁竞争导致的性能下降

  4. 调试困难

    • 问题难以复现

    • 执行顺序不确定

2. Java多线程实现

2.1 继承 Thread 类

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

public class Main {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start(); // 启动线程
    }
}

2.2 实现 Runnable 接口

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

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

优势:避免单继承限制,更适合资源共享。

2.3 实现 Callable 接口(带返回值)

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        return "线程执行结果: " + Thread.currentThread().getName();
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        FutureTask<String> task = new FutureTask<>(new MyCallable());
        Thread thread = new Thread(task);
        thread.start();
        System.out.println(task.get()); // 获取返回值
    }
}

2.4 使用线程池(推荐方式)

ExecutorService executor = Executors.newFixedThreadPool(4);
executor.execute(() -> {
    System.out.println("Task running in thread pool");
});
executor.shutdown();

3.线程的生命周期

Java线程有以下6种状态(Thread.State枚举):

  1. NEW:已创建但未启动

  2. RUNNABLE:正在运行或可运行

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

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

  5. TIMED_WAITING:有限期等待(sleep()、wait(timeout))

  6. TERMINATED:线程已终止

状态转换

NEW → start() → RUNNABLE
RUNNABLE → 获取锁 → BLOCKED
RUNNABLE → wait()/join() → WAITING
RUNNABLE → sleep(timeout)/wait(timeout) → TIMED_WAITING
WAITING/TIMED_WAITING → notify()/interrupt()/超时 → RUNNABLE
BLOCKED → 获取锁 → RUNNABLE
RUNNABLE → 运行结束 → TERMINATED

4.线程同步机制

synchronized 关键字

对象锁

class Counter {
    private int count = 0;
    
    public synchronized void increment() {
        count++;
    }
    
    public synchronized int getCount() {
        return count;
    }
}

类锁

class StaticCounter {
    private static int count = 0;
    
    public static synchronized void increment() {
        count++;
    }
}

 同步代码块

public void doSomething() {
    // 非同步代码
    synchronized(this) {
        // 同步代码块
    }
}

同步方法: 

public synchronized void synchronizedMethod() {
    // 临界区代码
}

volatile关键字

作用

  • 保证变量的可见性

  • 禁止指令重排序

  • 不保证原子性

适用场景

class VolatileExample {
    private volatile boolean flag = false;
    
    public void start() {
        new Thread(() -> {
            while (!flag) {
                // 循环直到flag变为true
            }
            System.out.println("Flag is now true");
        }).start();
    }
    
    public void stop() {
        flag = true;
    }
}

 Lock接口

基本用法

class LockExample {
    private final Lock lock = new ReentrantLock();
    private int count = 0;
    
    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }
}

高级特性

// 尝试获取锁
if (lock.tryLock(1, TimeUnit.SECONDS)) {
    try {
        // 获取锁成功
    } finally {
        lock.unlock();
    }
} else {
    // 获取锁超时
}

// 可中断锁
lock.lockInterruptibly();

 

原子类

java.util.concurrent.atomic包提供原子操作类:

AtomicInteger counter = new AtomicInteger(0);

// 原子递增
counter.incrementAndGet();

// CAS操作
boolean updated = counter.compareAndSet(expect, update);

 同步工具类

  1. CountDownLatch

    CountDownLatch latch = new CountDownLatch(3);
    
    // 工作线程
    new Thread(() -> {
        // 工作
        latch.countDown();
    }).start();
    
    // 主线程等待
    latch.await();

  2. CyclicBarrier

    CyclicBarrier barrier = new CyclicBarrier(3, () -> {
        System.out.println("All threads reached barrier");
    });
    
    new Thread(() -> {
        // 工作
        barrier.await();
    }).start();

  3. Semaphore

    Semaphore semaphore = new Semaphore(3); // 允许3个线程同时访问
    
    semaphore.acquire();
    try {
        // 访问资源
    } finally {
        semaphore.release();
    }

5.线程间通信

1. 共享变量 + synchronized(同步锁) 
class SharedResource {
    private int value;
    private boolean available = false;

    public synchronized void produce(int val) {
        while (available) {
            try {
                wait(); // 释放锁,等待消费
            } catch (InterruptedException e) { /*...*/ }
        }
        value = val;
        available = true;
        notifyAll(); // 唤醒消费线程
    }

    public synchronized int consume() {
        while (!available) {
            try {
                wait(); // 等待生产
            } catch (InterruptedException e) { /*...*/ }
        }
        available = false;
        notifyAll(); // 唤醒生产线程
        return value;
    }
}

2. Lock + Condition(更灵活)
class SharedResource {
    private final Lock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();
    private int value;
    private boolean available = false;

    public void produce(int val) {
        lock.lock();
        try {
            while (available) {
                notFull.await(); // 等待非满条件
            }
            value = val;
            available = true;
            notEmpty.signal(); // 通知非空条件
        } finally {
            lock.unlock();
        }
    }

    public int consume() {
        lock.lock();
        try {
            while (!available) {
                notEmpty.await(); // 等待非空条件
            }
            available = false;
            notFull.signal(); // 通知非满条件
            return value;
        } finally {
            lock.unlock();
        }
    }
}
3. 阻塞队列 BlockingQueue(推荐)
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);

// 生产者
Runnable producer = () -> {
    try {
        queue.put(1); // 队列满时自动阻塞
    } catch (InterruptedException e) { /*...*/ }
};

// 消费者
Runnable consumer = () -> {
    try {
        int value = queue.take(); // 队列空时自动阻塞
    } catch (InterruptedException e) { /*...*/ }
};

new Thread(producer).start();
new Thread(consumer).start();
4. wait() / notify() 机制
  • wait():释放锁并进入等待状态

  • notify():随机唤醒一个等待线程

  • notifyAll():唤醒所有等待线程

必须配合 synchronized 使用,否则抛出 IllegalMonitorStateException

6.关键概念

方法/类作用说明
synchronized保证代码块/方法的原子性访问
volatile确保变量可见性(不保证原子性)
Thread.join()等待线程终止
Thread.yield()让出CPU时间(不释放锁)
Thread.sleep()休眠指定时间(不释放锁)

 7.总结

  1. 优先用 Runnable/Callable:避免继承局限性

  2. 使用线程池:管理线程生命周期(Executors 工具类)

  3. 避免死锁:按固定顺序获取锁,设置超时(tryLock()

  4. 同步最小化:缩小 synchronized 范围提升性能

通过合理使用多线程,可显著提升程序性能,但务必谨慎处理线程安全与协调问题!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值