今天学习线程的基本知识



总体学习大纲
在这里插入图片描述

1. 线程和进程区别??

进程是资源分配的最小单位,线程是 CPU 调度的最小单位。

  • 进程是资源的容器,线程是干活的人。
  • 进程是为了隔离(防止互相干扰),线程是为了共享(提高效率)。

2. 并发与并行区别??

并发(concurrent)是同一时间应对(dealing with)多件事情的能力

比如说:
处理一件事情,一个处理时间10分钟, 并发下,5个人处理这件事(5个线程),只需要两分钟。

并行(parallel)是同一时间动手做(doing)多件事情的能力

比如说:
我一个人同一时间内可以处理5件事情


3. 创建线程的方式有哪些???(高频)

  1. 继承Thread类,从写run方法
  2. 实现Runnable接口,从写run方法,但是使用方式有点不一样
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("线程通过实现Runnable接口运行");
    }

    public static void main(String[] args) {
        MyRunnable runnable = new MyRunnable();
        Thread thread = new Thread(runnable);
        thread.start();
    }
}
  1. 实现 Callable 接口 + FutureTask
    如果你的线程任务需要返回结果或抛出异常,就用这种方式。
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        // 任务执行后返回结果
        return "线程通过Callable接口运行,返回结果";
    }

    public static void main(String[] args) throws Exception {
        Callable<String> callable = new MyCallable();
        FutureTask<String> futureTask = new FutureTask<>(callable);
        Thread thread = new Thread(futureTask);
        thread.start();
        
        // 获取线程执行结果(会阻塞直到结果返回)
        String result = futureTask.get();
        System.out.println(result);
    }
}

核心优势: 支持返回值和异常捕获,适合需要任务结果的场景(如计算型任务)。

  1. 使用线程池(最推荐在生产环境使用)
    直接创建线程会频繁产生创建 / 销毁的开销,线程池可以复用线程,提高性能。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolDemo {
    public static void main(String[] args) {
        // 创建固定大小的线程池
        ExecutorService executor = Executors.newFixedThreadPool(3);
        
        // 提交任务给线程池
        for (int i = 0; i < 5; i++) {
            executor.submit(() -> {
                System.out.println("线程池中的线程运行:" + Thread.currentThread().getName());
            });
        }
        
        // 关闭线程池
        executor.shutdown();
    }
}

项目中用


3.1 创建线程方法runnable和callable

  • Runnable接口的run没有返回值
  • Callable接口的call方法有返回值,可以获取异步执行结果
  • Callable接口的call()方法允许抛出异常; 而Runnable接口的run()方法不可以向上抛出异常。

3.2 run方法和start方法区别

run方法只是普通方法,可以调用多次
start方法是启动该线程,启动后该代码就会执行run方法的任务,该线程不可以启动多次


4. 线程包括那些状态,状态是如何变化的??

线程状态在Thread类中的枚举State内部类

线程状态包括: 新建(new), 可运行(RUNNAbLE), 阻塞(BLOCKED),等待(WAITNG),时间等待(TIME_WALTING),终止(TERMINATED)。

状态的转换关系
在这里插入图片描述

  • 创建线程对象是新建状态
  • 调用了 start () 方法转变为可执行状态
  • 线程获取到了 CPU 的执行权,执行结束是终止状态
  • 在可执行状态的过程中,如果没有获取 CPU 的执行权,可能会切换其他状态
  • 如果没有获取锁(synchronized 或 lock)进入阻塞状态,获得锁再切换为可执行状态
  • 如果线程调用了 wait () 方法进入等待状态,其他线程调用 notify () 唤醒后可切换为可执行状态
  • 如果线程调用了 sleep (50) 方法,进入计时等待状态,到时间后可切换为可执行状态

5. 新建T1,T2,T3三个线程,如何保证他们的执行顺序??

方法一:join()方法
在这里插入图片描述


6. notify和notifyAll方法的区别???

  • notifyAll唤醒所有wait线程

  • notify唤醒所有wait线程


7. Java中的wait和sleep方法的不同???(高频)

wait () 的重载方法:

  • wait():无限等待,直到被唤醒;
  • wait(long timeout):超时自动唤醒(单位:毫秒),避免永久等待。

sleep () 的参数:

  • sleep(long millis):休眠指定毫秒;
  • sleep(long millis, int nanos):精确到纳秒(实际很少用)。

共同点

  • 都会让当前线程暂停一段时间,进入阻塞状态。
  • 都支持超时参数(wait(long timeout) 和 sleep(long millis)),可以在指定时间后自动恢复执行。
    不同点
  • wait是java.lang.Object的方法, sleep是java.lang.Thread的方法
  • wait必须在 synchronized 块中调用,且会释放持有的对象锁。sleep无需持有锁,调用时不会释放任何锁。
  • wait必须其他线程调用 notify()/notifyAll() 唤醒,或超时自动唤醒。sleep到达指定时间自动唤醒,或被中断唤醒。

8. 如何停止一个正在运行的线程???

两种方式:

「自定义标记」方式
原理: 通过一个共享的布尔变量作为停止标记,线程在循环中检查该变量,为 true 时主动退出。

注意: 标记变量需要用 volatile 修饰,确保多线程之间的可见性。

public class FlagDemo {
    // 用volatile保证可见性
    private static volatile boolean stopFlag = false;

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (!stopFlag) {
                System.out.println("线程运行中...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("线程已停止");
        });
        thread.start();

        // 3秒后设置停止标记
        Thread.sleep(3000);
        stopFlag = true;
    }
}

「中断标记」方式(最常用)
原理: 线程通过 isInterrupted() 方法检查中断标记,在合适的时机主动退出。
触发中断: 其他线程调用 thread.interrupt() 时,会给目标线程设置一个中断标记。
处理中断: 如果线程在 wait()、sleep() 等阻塞方法中被中断,会抛出 InterruptedException,此时需要捕获异常并退出循环。

public class InterruptDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            // 循环中检查中断标记
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("线程运行中...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // 捕获中断异常后,需要手动退出循环
                    System.out.println("线程被中断,准备退出");
                    break;
                }
            }
            System.out.println("线程已停止");
        });
        thread.start();

        // 3秒后中断线程
        Thread.sleep(3000);
        thread.interrupt();
    }
}

好了线程基础就到这里

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐