如何在Java中实现多线程编程

简介: Java多线程编程有三种主要方式:继承Thread类、实现Runnable接口、实现Callable接口(结合Future获取结果),推荐使用Runnable避免单继承限制。通过线程池(如ExecutorService)可高效管理线程,提升性能。多线程共享资源时需注意线程安全,使用synchronized或Lock机制保证数据一致性。适用于并发执行、异步计算等场景。

在Java中实现多线程编程主要有三种核心方式:继承Thread实现Runnable接口实现Callable接口(结合Future。此外,还可以通过线程池(ExecutorService)更高效地管理线程。以下是详细实现方法及代码示例:

一、继承Thread

Thread类是Java线程的基础类,通过继承它并重写run()方法定义线程执行逻辑,调用start()方法启动线程(而非直接调用run())。

// 1. 继承Thread类
class MyThread extends Thread {
   
    // 2. 重写run()方法,定义线程执行逻辑
    @Override
    public void run() {
   
        for (int i = 0; i < 5; i++) {
   
            // Thread.currentThread().getName()获取当前线程名称
            System.out.println(Thread.currentThread().getName() + ":执行第" + i + "次");
            try {
   
                Thread.sleep(500); // 线程休眠500ms(模拟耗时操作)
            } catch (InterruptedException e) {
   
                e.printStackTrace();
            }
        }
    }
}

public class ThreadDemo {
   
    public static void main(String[] args) {
   
        // 3. 创建线程对象
        MyThread thread1 = new MyThread();
        MyThread thread2 = new MyThread();

        // 设置线程名称(可选)
        thread1.setName("线程A");
        thread2.setName("线程B");

        // 4. 启动线程(调用start(),而非run())
        thread1.start();
        thread2.start();
    }
}

输出(顺序可能不同,体现线程并发)

线程A:执行第0次
线程B:执行第0次
线程A:执行第1次
线程B:执行第1次
...

二、实现Runnable接口

Runnable是函数式接口(仅含run()方法),通过实现它定义线程逻辑,再将实例传入Thread类启动。推荐此方式,因为Java单继承,但可多实现。

// 1. 实现Runnable接口
class MyRunnable implements Runnable {
   
    // 2. 实现run()方法
    @Override
    public void run() {
   
        for (int i = 0; i < 5; i++) {
   
            System.out.println(Thread.currentThread().getName() + ":执行第" + i + "次");
            try {
   
                Thread.sleep(500);
            } catch (InterruptedException e) {
   
                e.printStackTrace();
            }
        }
    }
}

public class RunnableDemo {
   
    public static void main(String[] args) {
   
        // 3. 创建Runnable实例
        MyRunnable runnable = new MyRunnable();

        // 4. 将Runnable传入Thread,创建线程对象
        Thread thread1 = new Thread(runnable, "线程C");
        Thread thread2 = new Thread(runnable, "线程D");

        // 5. 启动线程
        thread1.start();
        thread2.start();
    }
}

特点:多个线程可共享同一个Runnable实例的资源(如成员变量),适合多线程协作。

三、实现Callable接口(带返回值)

Callable接口与Runnable类似,但允许线程执行后返回结果,且可抛出受检异常。需结合FutureFutureTask获取结果。

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

// 1. 实现Callable接口,指定返回值类型(此处为Integer)
class MyCallable implements Callable<Integer> {
   
    private int num;

    public MyCallable(int num) {
   
        this.num = num;
    }

    // 2. 实现call()方法(有返回值)
    @Override
    public Integer call() throws Exception {
   
        int sum = 0;
        for (int i = 1; i <= num; i++) {
   
            sum += i;
        }
        System.out.println(Thread.currentThread().getName() + ":计算完成");
        return sum; // 返回结果
    }
}

public class CallableDemo {
   
    public static void main(String[] args) throws ExecutionException, InterruptedException {
   
        // 3. 创建Callable实例
        MyCallable callable = new MyCallable(100);

        // 4. 用FutureTask包装Callable(FutureTask实现了Future和Runnable)
        FutureTask<Integer> futureTask = new FutureTask<>(callable);

        // 5. 传入Thread启动
        Thread thread = new Thread(futureTask, "计算线程");
        thread.start();

        // 6. 调用get()获取结果(会阻塞当前线程,直到子线程执行完毕)
        int result = futureTask.get();
        System.out.println("1~100的和:" + result); // 输出:5050
    }
}

特点:适合需要线程返回结果的场景(如异步计算)。

四、线程池(ExecutorService

频繁创建/销毁线程会消耗资源,线程池可复用线程,提高效率。通过Executors工具类创建线程池(实际开发中推荐ThreadPoolExecutor自定义)。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolDemo {
   
    public static void main(String[] args) {
   
        // 1. 创建固定大小的线程池(3个线程)
        ExecutorService executor = Executors.newFixedThreadPool(3);

        // 2. 提交任务(Runnable或Callable)
        for (int i = 0; i < 5; i++) {
   
            final int taskNum = i;
            executor.submit(new Runnable() {
   
                @Override
                public void run() {
   
                    System.out.println(Thread.currentThread().getName() + ":执行任务" + taskNum);
                    try {
   
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
   
                        e.printStackTrace();
                    }
                }
            });
        }

        // 3. 关闭线程池(不再接受新任务,等待现有任务完成)
        executor.shutdown();
    }
}

常用线程池类型

  • newFixedThreadPool(n):固定大小的线程池
  • newCachedThreadPool():可缓存的线程池(线程数动态调整)
  • newSingleThreadExecutor():单线程池(任务串行执行)
  • newScheduledThreadPool(n):支持定时/周期性任务的线程池

五、线程常用方法

方法 说明
start() 启动线程(底层调用run()
run() 线程执行逻辑(需重写)
sleep(long ms) 让当前线程休眠指定毫秒(不会释放锁)
join() 等待该线程执行完毕后,再继续执行其他线程
yield() 让出CPU资源,让其他线程优先执行
setPriority(int) 设置线程优先级(1~10,默认5)
isAlive() 判断线程是否存活

六、线程安全问题

多线程共享资源时可能出现数据不一致,需通过同步机制解决:

  • synchronized关键字(同步方法/代码块)
  • Lock接口(如ReentrantLock

示例(synchronized解决线程安全)

class Counter {
   
    private int count = 0;

    // 同步方法:保证同一时间只有一个线程执行
    public synchronized void increment() {
   
        count++;
    }

    public int getCount() {
   
        return count;
    }
}

public class ThreadSafety {
   
    public static void main(String[] args) throws InterruptedException {
   
        Counter counter = new Counter();
        Thread t1 = new Thread(() -> {
   
            for (int i = 0; i < 10000; i++) {
   
                counter.increment();
            }
        });
        Thread t2 = new Thread(() -> {
   
            for (int i = 0; i < 10000; i++) {
   
                counter.increment();
            }
        });

        t1.start();
        t2.start();
        t1.join(); // 等待t1完成
        t2.join(); // 等待t2完成

        System.out.println("最终计数:" + counter.getCount()); // 正确输出20000(无同步可能小于20000)
    }
}

总结

  • 简单场景:用ThreadRunnable(推荐Runnable)。
  • 需要返回值:用Callable + Future
  • 高效管理线程:用线程池。
  • 多线程共享资源:需考虑线程安全(synchronizedLock)。

多线程编程的核心是并发协作资源同步,实际开发中需根据场景选择合适的实现方式。

相关文章
|
2月前
|
人工智能 自然语言处理 安全
SOFA AI 网关基于 Higress 的落地实践
SOFA 商业化团队为满足客户 AI 业务的发展需求,基于开源 Higress 内核构建,推出了 SOFA AI 网关,专为 SOFA 场景深度优化、能力增强,是面向 AI 需求的智能网关解决方案。
222 19
|
13天前
|
文字识别 安全 程序员
PowerToys微软官方效率工具实操教程!Windows系统增强神器!
PowerToys是微软官方推出的免费开源工具集,集成20余款高效插件,如窗口管理、快速启动、批量重命名、OCR文字提取等,显著提升Windows使用体验,支持多屏协作、快捷操作,安全稳定,持续更新,适合各类用户优化工作效率。
144 6
|
监控 网络协议 物联网
你知道什么是物联网MQTT么?
你知道什么是物联网MQTT么?
912 0
|
Android开发 开发者 UED
个人开发 App 成功上架手机应用市场的关键步骤
个人开发 App 成功上架手机应用市场的关键步骤
|
2月前
|
IDE Java 编译器
java编程最基础学习
Java入门需掌握:环境搭建、基础语法、面向对象、数组集合与异常处理。通过实践编写简单程序,逐步深入学习,打牢编程基础。
214 1
|
15天前
|
人工智能 前端开发 数据挖掘
AI学习全景图:从大模型到RAG,从工具到变现,一条从0到1的路线
告别碎片化学习!本文系统梳理AI知识五层结构:从基础认知到商业变现,提供完整学习路径与优质资源链接。帮你构建AI知识网络,实现从工具使用到能力落地的跃迁。
|
23天前
|
JSON NoSQL Java
RedisTemplate和StringRedisTemplate的区别及个人见解
RedisTemplate和StringRedisTemplate的区别及个人见解
112 4
|
算法 Java
JAVA 雪花算法 唯一ID生成工具类
JAVA 雪花算法 唯一ID生成工具类
2892 0
|
17天前
|
Java 数据安全/隐私保护
分享一些Java面向对象的实际案例
Java面向对象案例通过校园管理和电商系统,展现封装、继承、多态的协同:封装保护数据,继承复用代码,多态实现灵活扩展,贴近实际应用,体现OOP核心思想。(238字)
69 0
|
17天前
|
SQL 人工智能 自然语言处理
Navicat AI 助理实战指南:开启智能数据库管理新时代
Navicat集成AI助理,支持自然语言生成SQL、智能优化与错误诊断。通过云端或本地模型(如Ollama)实现高效安全的数据库管理,提升开发效率60%以上,助力开发者迈向智能工作流新时代。
128 0

热门文章

最新文章