java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > java创建线程

Java 并发编程创建线程的四种方式示例详解

作者:钟琛

本文对比Java创建线程的四种方式:继承Thread类(单继承限制)、实现Runnable接口(灵活推荐)、实现Callable接口(支持返回值)、使用线程池(最佳实践,资源管理高效),推荐优先使用线程池提升系统稳定性与资源利用率,感兴趣的朋友一起看看吧

1. 继承 Thread 类

特点

class MyThread extends Thread {
    @Override
    public void run() {
        // 线程执行逻辑
        System.out.println("继承Thread类的线程: " + Thread.currentThread().getName());
    }
}
public class ThreadDemo {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start(); // 启动线程
    }
}

2. 实现 Runnable 接口(推荐)

特点

public class RunnableDemo {
    public static void main(String[] args) {
        // 方式1:匿名内部类
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Runnable匿名内部类线程: " + Thread.currentThread().getName());
            }
        }).start();
        // 方式2:Lambda表达式(推荐)
        new Thread(() -> {
            System.out.println("Runnable Lambda线程: " + Thread.currentThread().getName());
        }).start();
        // 方式3:实现类
        Runnable task = new MyRunnable();
        new Thread(task).start();
    }
}
class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("实现Runnable接口的线程: " + Thread.currentThread().getName());
    }
}

3. 实现 Callable 接口(带返回值)

特点

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创建Callable任务
        Callable<String> callableTask = () -> {
            Thread.sleep(1000);
            return "Callable线程执行结果: " + Thread.currentThread().getName();
        };
        // 包装为FutureTask
        FutureTask<String> futureTask = new FutureTask<>(callableTask);
        // 启动线程
        new Thread(futureTask).start();
        // 获取结果(会阻塞直到任务完成)
        String result = futureTask.get();
        System.out.println(result);
    }
}

4. 使用线程池(最佳实践)

特点

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ThreadPoolDemo {
    public static void main(String[] args) throws Exception {
        // 创建固定大小线程池
        ExecutorService executor = Executors.newFixedThreadPool(3);
        // 提交Runnable任务
        executor.execute(() -> {
            System.out.println("线程池执行Runnable任务: " + Thread.currentThread().getName());
        });
        // 提交Callable任务
        Future<String> future = executor.submit(() -> {
            Thread.sleep(500);
            return "线程池执行Callable任务结果: " + Thread.currentThread().getName();
        });
        // 获取Callable结果
        System.out.println(future.get());
        // 关闭线程池
        executor.shutdown();
    }
}

5.四种方式对比

创建方式返回值异常处理资源消耗灵活性推荐指数
继承 Thread受限于重写⭐☆☆☆
实现 Runnable自由处理⭐⭐⭐☆
实现 Callable自由处理⭐⭐⭐⭐
线程池统一管理极高⭐⭐⭐⭐⭐

6.线程池的进阶用法

自定义线程池

import java.util.concurrent.*;
public class CustomThreadPool {
    public static void main(String[] args) {
        // 创建自定义线程池
        ExecutorService customPool = new ThreadPoolExecutor(
            4, // 核心线程数
            10, // 最大线程数
            60, // 空闲线程存活时间
            TimeUnit.SECONDS, // 时间单位
            new ArrayBlockingQueue<>(100), // 任务队列
            Executors.defaultThreadFactory(), // 线程工厂
            new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
        );
        // 提交任务
        for (int i = 0; i < 20; i++) {
            int taskId = i;
            customPool.execute(() -> {
                System.out.println("执行任务 " + taskId + " 线程: " + Thread.currentThread().getName());
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }
        // 优雅关闭
        customPool.shutdown();
        try {
            if (!customPool.awaitTermination(60, TimeUnit.SECONDS)) {
                customPool.shutdownNow();
            }
        } catch (InterruptedException e) {
            customPool.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
}

线程池关键参数解析

参数说明
核心线程数线程池长期维持的线程数
最大线程数线程池允许的最大线程数
空闲存活时间非核心线程空闲超过此时间将被回收
任务队列存放待执行任务的阻塞队列
线程工厂用于创建新线程,可自定义线程名称、优先级等
拒绝策略当任务太多时的处理策略(Abort-抛异常, Discard-丢弃, CallerRuns-调用者执行)

四种拒绝策略对比

策略行为
AbortPolicy默认策略,抛出 RejectedExecutionException
DiscardPolicy静默丢弃新任务
DiscardOldestPolicy丢弃队列中最老的任务,然后重试提交
CallerRunsPolicy由调用者线程(提交任务的线程)直接执行该任务

实践建议

7.线程池任务处理流程图

最大处理能力 = 核心线程数 + 任务队列容量 + (最大线程数 - 核心线程数)

 任务的执行顺序不一定与提交顺序一致

举个例子(假设任务执行时间较长,核心线程一直被任务1,任务2占用):核心线程数是2,最大线程数是10,任务队列长5;那么最大处理能力为15(2+5+8),第16个任务执行拒绝策略,任务3会在任务队列里排队,而任务8在发现核心线程都在工作时且任务队列已满,但线程数小于最大线程的情况下,会创建非核心线程,并直接开始执行任务8,所以说任务8会比任务3更快执行,因此任务的执行顺序不一定与提交顺序一致

到此这篇关于Java 并发编程:创建线程的 4 种方式的文章就介绍到这了,更多相关java创建线程内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文