1. 什么是多线程,有什么作用,不同的多线程创建方式

1.1 多线程概念

  • 线程(Thread):程序执行的最小单元,属于进程内部。

  • 多线程:一个进程中有多个线程同时运行,各自执行不同任务。

  • 作用

    1. 提升程序的并发能力(多个任务“同时”处理)。

    2. 提高资源利用率(CPU 空闲时执行其他任务)。

    3. 提升响应速度(避免 GUI 卡死)。

    4. 适应多核 CPU(并行执行任务)。


1.2 Java 线程的创建方式(全写 → 简写)

方式 1:继承 Thread 类
// 全写方式
class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("线程名:" + Thread.currentThread().getName());
    }
}

public class Demo1 {
    public static void main(String[] args) {
        MyThread t1 = new MyThread(); // 创建线程对象
        t1.start(); // 启动线程
    }
}

// 简写方式(匿名内部类)
new Thread() {
    @Override
    public void run() {
        System.out.println("匿名Thread线程:" + Thread.currentThread().getName());
    }
}.start();


方式 2:实现 Runnable 接口
// 全写方式
class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Runnable线程:" + Thread.currentThread().getName());
    }
}

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

// 简写方式(Lambda 表达式)
new Thread(() -> System.out.println("Lambda Runnable线程:" + Thread.currentThread().getName())).start();


方式 3:实现 Callable 接口 + FutureTask
// 全写方式
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

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

public class Demo3 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<String> task = new FutureTask<>(new MyCallable());
        new Thread(task).start();
        System.out.println(task.get()); // 获取返回值(阻塞)
    }
}

// 简写方式(Lambda)
FutureTask<String> task = new FutureTask<>(() -> "Lambda Callable:" + Thread.currentThread().getName());
new Thread(task).start();
System.out.println(task.get());


方式 4:线程池(ExecutorService)
// 全写方式
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

ExecutorService pool = Executors.newFixedThreadPool(2); // 固定大小线程池
pool.execute(() -> System.out.println("线程池Runnable任务:" + Thread.currentThread().getName()));
pool.shutdown();
// 简写方式(直接提交任务)
Executors.newCachedThreadPool().execute(() -> System.out.println("简写线程池任务"));

2. 不同线程创建方式的优缺点 & 适用场景

创建方式 优点 缺点 适用场景
继承 Thread 编写简单 单继承限制 任务简单、一次性线程
实现 Runnable 可继承其他类、共享数据方便 无返回值 多线程共享数据
实现 Callable 可返回值、可抛异常 代码复杂 异步计算、需要结果的任务
线程池 线程可复用、性能好 需管理线程池 高并发任务、长期运行服务


3. 线程的常用方法(含参数说明)

方法 参数 作用 注意
start() 启动线程 不能重复调用
run() 执行任务逻辑 直接调用不是多线程
sleep(long millis) 毫秒 暂停线程执行 不释放锁
yield() 暂时让出 CPU 可能立即再次获取 CPU
join() 无 / 带毫秒 等待线程结束 阻塞当前线程
interrupt() 中断线程 设置中断标志位
isAlive() 判断线程是否在运行 -
setPriority(int) 1~10 设置优先级 仅作建议


4. 线程安全问题 & 解决方案

常见问题

  • 多线程同时修改共享变量(i++)

  • 非线程安全集合(ArrayListHashMap

  • 文件写入冲突

解决方案

方案 关键字/类 特点
synchronized 修饰方法/代码块 简单、JVM 内置锁
Lock ReentrantLock 灵活、可定时可中断
volatile 修饰变量 保证可见性,不保证原子性
原子类 AtomicInteger 高性能原子操作
并发集合 ConcurrentHashMap 内置安全机制


5. 线程同步

定义

确保多线程按顺序安全访问共享资源。

实现方式

// synchronized 方法
synchronized void add() { count++; }

// synchronized 代码块
synchronized (this) { count++; }

// Lock
Lock lock = new ReentrantLock();
lock.lock();
try { count++; } finally { lock.unlock(); }


6. 线程池

解决的问题

  • 减少频繁创建和销毁线程的开销

  • 控制最大并发数

  • 管理线程生命周期

创建方式

ExecutorService pool = Executors.newFixedThreadPool(4);
pool.submit(() -> System.out.println("任务"));
pool.shutdown();

推荐手动创建

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    2, 4, 60, TimeUnit.SECONDS,
    new ArrayBlockingQueue<>(100),
    Executors.defaultThreadFactory(),
    new ThreadPoolExecutor.AbortPolicy()
);

注意事项

  • 合理设置线程数(CPU密集:核数+1,IO密集:2倍核数)

  • 不要使用无限队列

  • 记得 shutdown()


7. 并发 vs 并行

概念 特点 例子
并发 宏观同时、微观交替 一个厨师炒两个菜,交替翻锅
并行 真正同时执行 两个厨师同时炒两个菜

8. Mermaid 思维导图

  root((Java 多线程知识大全))
    概念与作用
      线程(线程 = 执行的最小单位)
      多线程(同一进程的多个执行流)
      作用
        并发处理
        提高响应性(如 GUI)
        资源利用率提升
        适配多核实现并行
      注意事项
        线程切换开销
        并发不一定提升性能
    创建线程方式
      继承Thread
      实现Runnable
      Callable+FutureTask
      线程池(ExecutorService)
    何时用哪种
      一次性简单任务 -> 继承Thread或Runnable
      需要返回值或异常 -> Callable
      高并发、长期服务 -> 线程池
    常用方法(参数说明)
      start()
      run()
      sleep(long millis)
      yield()
      join()
      interrupt()
      isAlive()
      setPriority()
    线程安全问题
      数据竞争(race condition)
      可见性问题
      原子性缺失
      非线程安全集合
    线程同步与解决方案
      synchronized
        方法锁(修饰实例/静态方法)
        代码块锁(指定锁对象)
      ReentrantLock
        lock()/unlock()
        tryLock()/lockInterruptibly()
        可公平锁
      volatile
        保证变量可见性
        禁止指令重排
        不保证原子性
      原子类(Atomic)
        AtomicInteger
        AtomicReference
        原子更新方法(getAndIncrement等)
      并发集合
        ConcurrentHashMap
        CopyOnWriteArrayList
        阻塞队列(LinkedBlockingQueue等)
    线程池详解
      Executors 工厂方法
      推荐 ThreadPoolExecutor(核心参数)
      调优建议(CPU密集 vs IO密集)
      注意事项
    并发 vs 并行
      并发(同时间窗口内多任务, 交替执行)
      并行(多核真正同时执行)

9.线程关键创建方式(继承 Thread,实现 Runnable,Callable<V> + FutureTask<V>,线程池 )的 全写 → 简写 示例(带注释)

下面示例可直接在 Java 8+ 环境运行(部分示例需要 throws Exception)。每段代码包含注释说明参数和用法。

1) 继承 Thread(全写 → 匿名 / 简写)

// 全写方式:继承 Thread 类(适合演示,但不推荐用于实际复杂系统)
// 优点:写法直观;缺点:无法继承其他类,不利于任务复用
class MyThread extends Thread {
    // run() 是线程启动后的执行体
    @Override
    public void run() {
        // Thread.currentThread().getName() 获取当前线程名
        System.out.println("MyThread running, name=" + Thread.currentThread().getName());
        // 模拟工作
        for (int i = 0; i < 3; i++) {
            System.out.println("MyThread => " + i);
            try { Thread.sleep(200); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
        }
    }
}

public class ThreadExtendDemo {
    public static void main(String[] args) {
        MyThread t = new MyThread(); // 创建线程对象
        t.setName("Worker-Thread");  // 可选:设置线程名字
        t.start(); // 启动线程(注意:调用 start(),不要直接调用 run())
    }
}

// 匿名内部类(简写):
new Thread() {
    @Override
    public void run() {
        System.out.println("匿名 Thread 执行: " + Thread.currentThread().getName());
    }
}.start();

2) 实现 Runnable(全写 → Lambda 简写)

// 全写方式:实现 Runnable 接口,用 Thread 包装(适合共享同一 Runnable 实例)
class MyRunnable implements Runnable {
    private final String name;
    MyRunnable(String name) { this.name = name; }

    @Override
    public void run() {
        System.out.println("MyRunnable(" + name + ") start, thread=" + Thread.currentThread().getName());
        // 模拟任务
        try { Thread.sleep(150); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
        System.out.println("MyRunnable(" + name + ") end");
    }
}

public class RunnableDemo {
    public static void main(String[] args) {
        Runnable r = new MyRunnable("task1");
        Thread t = new Thread(r, "runnable-thread-1"); // Thread(Runnable target, String name)
        t.start();
    }
}

// Lambda 简写(Java 8+)
new Thread(() -> {
    System.out.println("Lambda Runnable 执行, thread=" + Thread.currentThread().getName());
}).start();

3) Callable<V> + FutureTask<V>(全写 → Lambda)

import java.util.concurrent.*;

// 全写方式:Callable 可以返回结果并抛异常;FutureTask 可包装 Callable 交给 Thread 执行
class MyCallable implements Callable<String> {
    private final int id;
    MyCallable(int id) { this.id = id; }

    @Override
    public String call() throws Exception {
        // 可以抛出异常,调用者通过 Future#get 得到异常
        Thread.sleep(200); // 模拟耗时计算
        return "Result-from-Callable-" + id + " by thread=" + Thread.currentThread().getName();
    }
}

public class CallableDemo {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        Callable<String> callable = new MyCallable(1);
        FutureTask<String> future = new FutureTask<>(callable);
        Thread t = new Thread(future, "callable-thread");
        t.start();
        // future.get() 会阻塞直到结果可用或被中断
        String result = future.get();
        System.out.println("Got result: " + result);
    }
}

// Lambda 简写
FutureTask<String> ft = new FutureTask<>(() -> {
    Thread.sleep(100);
    return "Lambda Callable result, thread=" + Thread.currentThread().getName();
});
new Thread(ft).start();
System.out.println(ft.get()); // 阻塞获取

4) 线程池(ThreadPoolExecutor 推荐写法;并给出简写 Executors 示例)

import java.util.concurrent.*;

// 推荐:手动构造 ThreadPoolExecutor,便于精细调优
public class ThreadPoolDemo {
    public static void main(String[] args) {
        int corePoolSize = 2;           // 核心线程数
        int maximumPoolSize = 4;        // 最大线程数
        long keepAlive = 60L;           // 非核心线程空闲保活时间
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(100); // 有界队列
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy(); // 拒绝策略(抛异常)

        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                corePoolSize, maximumPoolSize,
                keepAlive, unit,
                workQueue, threadFactory, handler
        );

        // 提交 Runnable(不返回值)
        executor.execute(() -> {
            System.out.println("Pool task run by " + Thread.currentThread().getName());
        });

        // 提交 Callable(可返回 Future)
        Future<Integer> f = executor.submit(() -> {
            Thread.sleep(100);
            return 123;
        });

        try {
            System.out.println("Callable result: " + f.get());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } finally {
            // 关闭线程池,已提交任务会执行完再关闭
            executor.shutdown();
        }
    }
}

// 简写(注意:Executors 的工厂方法有时会隐藏风险,如 newFixedThreadPool 返回的队列为无界):
ExecutorService pool = Executors.newFixedThreadPool(4);
pool.submit(() -> System.out.println("简单线程池执行: " + Thread.currentThread().getName()));
pool.shutdown();

10. 线程同步方式 Java 示例(详细注释)

1) synchronized 示例

public class SyncExample {
    private int count = 0;

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

    // 同步静态方法(锁类对象 Class<SyncExample>)
    public static synchronized void staticIncrement() {
        // 静态共享资源逻辑
    }

    // 同步代码块(可指定锁对象)
    public void blockIncrement() {
        synchronized (this) { // 锁当前实例
            count++;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SyncExample ex = new SyncExample();

        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) ex.increment();
        };

        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);
        t1.start(); t2.start();
        t1.join(); t2.join();

        System.out.println("最终count=" + ex.count); // 正确输出2000
    }
}


2) ReentrantLock 示例

import java.util.concurrent.locks.ReentrantLock;

public class LockExample {
    private int count = 0;
    private final ReentrantLock lock = new ReentrantLock(true); // 公平锁:先来先得

    public void increment() {
        lock.lock(); // 获取锁(可响应中断、可尝试获取)
        try {
            count++;
        } finally {
            lock.unlock(); // 一定要在 finally 中释放锁
        }
    }

    public static void main(String[] args) throws InterruptedException {
        LockExample ex = new LockExample();

        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) ex.increment();
        };

        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);
        t1.start(); t2.start();
        t1.join(); t2.join();

        System.out.println("最终count=" + ex.count);
    }
}


3) volatile 示例

public class VolatileExample {
    private volatile boolean running = true; // 保证线程间可见性

    public void runTask() {
        while (running) {
            // 循环体逻辑
        }
        System.out.println("线程停止");
    }

    public void stopTask() {
        running = false; // 主线程修改后,工作线程能立即看到变化
    }

    public static void main(String[] args) throws InterruptedException {
        VolatileExample ex = new VolatileExample();
        Thread t = new Thread(ex::runTask);
        t.start();

        Thread.sleep(1000); // 运行1秒
        ex.stopTask(); // 通过volatile通知线程停止
    }
}

⚠️ 注意:volatile 不能保证 count++ 这种操作的原子性,只能保证可见性。


4) 原子类 AtomicInteger 示例

import java.util.concurrent.atomic.AtomicInteger;

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

    public void increment() {
        count.incrementAndGet(); // 原子自增
    }

    public static void main(String[] args) throws InterruptedException {
        AtomicExample ex = new AtomicExample();

        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) ex.increment();
        };

        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);
        t1.start(); t2.start();
        t1.join(); t2.join();

        System.out.println("最终count=" + ex.count.get()); // 2000
    }
}


5) 并发集合 ConcurrentHashMap 示例

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentMapExample {
    public static void main(String[] args) throws InterruptedException {
        ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();

        Runnable writer = () -> {
            for (int i = 0; i < 1000; i++) {
                map.put("key" + i, i);
            }
        };

        Thread t1 = new Thread(writer);
        Thread t2 = new Thread(writer);
        t1.start(); t2.start();
        t1.join(); t2.join();

        System.out.println("Map大小=" + map.size()); // 可能是1000(覆盖),线程安全
    }
}

Logo

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

更多推荐