Java多线程创建方式全解析

Java多线程创建方式及相关问题解析

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 内置锁
LockReentrantLock灵活、可定时可中断
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(覆盖),线程安全
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星空下的DeppBing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值