多线程基础

一、线程启动方式(4种)

1. 继承 Thread 类(基础方式)

  • 步骤
    1. 自定义类继承 Thread,重写 run() 方法(线程执行体)。
    2. 创建子类实例,调用 start() 方法启动线程。
  • 示例
    public class MyThread extends Thread {  
        @Override  
        public void run() {  
            System.out.println("线程 " + getName() + " 启动");  
        }  
    }  
    // 启动  
    new MyThread().start();  
    
  • 特点
    • 子类化 Thread,耦合度高(Java 单继承限制),不推荐用于资源共享场景。

2. 实现 Runnable 接口(推荐)

  • 步骤
    1. 自定义类实现 Runnable,重写 run() 方法。
    2. 创建 Runnable 实例,作为参数传入 Thread 构造器,调用 start()
  • 示例
    public class MyRunnable implements Runnable {  
        @Override  
        public void run() {  
            System.out.println("Runnable 线程启动");  
        }  
    }  
    // 启动  
    new Thread(new MyRunnable()).start();  
    
  • 特点
    • 解耦线程与任务(线程是执行载体,任务是具体逻辑),支持资源共享(多个线程可共享同一个 Runnable 实例)。

3. 使用 Callable + Future(带返回值)

  • 步骤
    1. 自定义类实现 Callable<V>,重写 call() 方法(可抛出异常,有返回值)。
    2. 通过 FutureTask 包装 Callable,传入 Thread 启动,或通过 ExecutorService 提交。
  • 示例
    import java.util.concurrent.Callable;  
    import java.util.concurrent.FutureTask;  
    
    public class MyCallable implements Callable<Integer> {  
        @Override  
        public Integer call() throws Exception {  
            return 1 + 2; // 返回计算结果  
        }  
    }  
    // 启动  
    FutureTask<Integer> futureTask = new FutureTask<>(new MyCallable());  
    new Thread(futureTask).start();  
    Integer result = futureTask.get(); // 获取返回值(阻塞直到结果可用)  
    
  • 特点
    • 支持返回值和异常处理,适合需要线程执行结果的场景。

4. 使用线程池(ExecutorService,推荐)

  • 步骤
    1. 通过 Executors 工具类创建线程池(如 newFixedThreadPool)。
    2. 提交任务(RunnableCallable)到线程池,由池管理线程生命周期。
  • 示例
    import java.util.concurrent.ExecutorService;  
    import java.util.concurrent.Executors;  
    
    ExecutorService executor = Executors.newFixedThreadPool(5);  
    executor.submit(new MyRunnable()); // 提交 Runnable 任务  
    executor.submit(new MyCallable()); // 提交 Callable 任务  
    executor.shutdown(); // 关闭线程池  
    
  • 特点
    • 复用线程,减少创建/销毁开销,控制并发数量,适合高并发场景。

二、Thread 类常用方法

1. 线程控制方法

方法名 作用 类型
start() 启动线程(进入就绪状态,等待 CPU 调度) 实例方法
run() 线程执行体(子类重写,默认无操作) 实例方法
join() 等待当前线程结束后,主线程再继续执行(可传超时参数) 实例方法
sleep(long ms) 让线程睡眠指定毫秒,释放 CPU 时间片(不会释放锁) 静态方法
yield() 提示线程让出 CPU(建议性,不一定生效) 静态方法
isAlive() 判断线程是否处于活动状态(已启动且未终止) 实例方法
setDaemon(boolean on) 设置为守护线程(如垃圾回收线程,主线程结束则守护线程自动终止) 实例方法

2. 线程状态相关

  • getState():获取线程状态(NEW/RUNNABLE/BLOCKED/WAITING/TIMED_WAITING/TERMINATED)。
  • interrupt():中断线程(设置中断标志,不直接终止线程)。

三、线程交互(线程间通信)

1. wait()/notify()/notifyAll()

  • 作用:实现线程间的协作(如生产者-消费者模型),需配合 synchronized 使用。
  • 规则
    • 只能在 同步块(synchronized 中调用。
    • wait():当前线程释放锁,进入等待队列,直到被 notify()/notifyAll() 唤醒。
    • notify():唤醒等待队列中的一个线程;notifyAll():唤醒所有等待线程。
  • 示例(生产者-消费者)
    public class ProducerConsumer {  
        private static final Object lock = new Object();  
        private static int count = 0;  
    
        // 生产者  
        public static class Producer implements Runnable {  
            @Override  
            public void run() {  
                synchronized (lock) {  
                    while (count >= 1) { // 避免虚假唤醒,用 while 而非 if  
                        try {  
                            lock.wait(); // 等待消费者处理  
                        } catch (InterruptedException e) {  
                            e.printStackTrace();  
                        }  
                    }  
                    count++;  
                    System.out.println("生产后 count = " + count);  
                    lock.notifyAll(); // 唤醒消费者  
                }  
            }  
        }  
    
        // 消费者  
        public static class Consumer implements Runnable {  
            @Override  
            public void run() {  
                synchronized (lock) {  
                    while (count <= 0) {  
                        try {  
                            lock.wait(); // 等待生产者生产  
                        } catch (InterruptedException e) {  
                            e.printStackTrace();  
                        }  
                    }  
                    count--;  
                    System.out.println("消费后 count = " + count);  
                    lock.notifyAll(); // 唤醒生产者  
                }  
            }  
        }  
    }  
    

2. CountDownLatch/CyclicBarrier(并发工具类)

  • CountDownLatch:多个线程等待某个事件完成(如主线程等待所有子线程结束)。
  • CyclicBarrier:多个线程相互等待,到达某个屏障点后一起执行。

四、线程中断机制

1. 中断标志(Interrupt Flag)

  • 每个线程有一个 中断标志位(布尔值),默认 false
  • interrupt():调用后设置标志为 true,不直接终止线程。

2. 检测中断的方式

方法名 作用
isInterrupted() 获取当前线程的中断标志(不会清除标志)
interrupted() 获取当前线程的中断标志,并清除标志(静态方法,通常在 catch 中使用)

3. 处理中断的场景

  • 场景 1:线程处于阻塞状态(如 sleep/join/wait

    • 调用 interrupt() 会抛出 InterruptedException,需在 catch 中处理(清除标志为 false)。
    try {  
        Thread.sleep(1000);  
    } catch (InterruptedException e) {  
        Thread.currentThread().interrupt(); // 重新设置中断标志,传递给上层  
        e.printStackTrace();  
    }  
    
  • 场景 2:线程在运行中(非阻塞)

    • 手动检测中断标志,主动终止逻辑。
    while (!Thread.currentThread().isInterrupted()) {  
        // 正常业务逻辑  
    }  
    System.out.println("线程被中断,结束运行");  
    

4. 注意事项

  • 中断机制是 协作式 的,线程需自行处理中断标志,无法强制终止线程(stop() 已过时,可能导致资源泄漏)。
  • 守护线程(setDaemon(true))会随主线程结束而终止,无需手动中断。

总结

  • 线程启动Runnable 和线程池是主流,支持解耦和资源共享;Callable 用于需要返回值的场景。
  • 线程交互wait/notify 是基础,结合 synchronized 实现协作;并发工具类(如 CountDownLatch)简化复杂场景。
  • 中断机制:通过设置中断标志通知线程终止,需结合业务逻辑处理,避免强制终止。
JUC编程 文章被收录于专栏

JUC 是 Java.util.concurrent 包的简称,它是 Java 5 引入的一个用于处理并发编程的工具包,为 Java 开发者提供了一系列用于高效处理并发任务的类和接口,极大地简化了多线程编程的复杂性。

全部评论

相关推荐

不愿透露姓名的神秘牛友
06-24 16:03
欲挽天倾:专业毫无意义的 找工作都是看学校title的
点赞 评论 收藏
分享
评论
1
4
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务