当前位置: 首页 > news >正文

多线程学习之路

多线程的创建方式主要有以下几种:

1. 继承 Thread 类

通过继承 Thread 类并重写 run() 方法来创建线程。

class MyThread extends Thread {
    @Override
    public void run() {
        // 线程执行的任务
        System.out.println("Thread is running");
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start(); // 启动线程
    }
}

2. 实现 Runnable 接口

通过实现 Runnable 接口并实现 run() 方法,然后将 Runnable 对象传递给 Thread 类的构造函数。

class MyRunnable implements Runnable {
    @Override
    public void run() {
        // 线程执行的任务
        System.out.println("Thread is running");
    }
}

public class Main {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start(); // 启动线程
    }
}

3. 实现 Callable 接口

通过实现 Callable 接口并实现 call() 方法,Callable 可以返回结果并抛出异常。通常与 ExecutorService 一起使用。

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        // 线程执行的任务
        return "Thread is running";
    }
}

public class Main {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        MyCallable myCallable = new MyCallable();
        Future<String> future = executor.submit(myCallable);

        try {
            String result = future.get(); // 获取线程执行结果
            System.out.println(result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } finally {
            executor.shutdown();
        }
    }
}

4. 使用线程池

通过 ExecutorService 和 Executors 工具类创建线程池,提交任务给线程池执行。

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

public class Main {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(5);

        for (int i = 0; i < 10; i++) {
            Runnable task = new MyRunnable();
            executor.execute(task);
        }

        executor.shutdown();
    }
}

5. 使用 CompletableFuture(Java 8+)

CompletableFuture 提供了更高级的异步编程方式,支持链式调用和组合多个异步任务。

import java.util.concurrent.CompletableFuture;

public class Main {
    public static void main(String[] args) {
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            // 异步执行的任务
            System.out.println("Thread is running");
        });

        future.join(); // 等待任务完成
    }
}

6. 使用 Timer 和 TimerTask

Timer 和 TimerTask 可以用于创建定时任务,TimerTask 实现了 Runnable 接口。

import java.util.Timer;
import java.util.TimerTask;

public class Main {
    public static void main(String[] args) {
        Timer timer = new Timer();
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                // 定时执行的任务
                System.out.println("Thread is running");
            }
        };

        timer.schedule(task, 0, 1000); // 延迟0毫秒,每隔1000毫秒执行一次
    }
}

7. 使用 ForkJoinPool(Java 7+)

ForkJoinPool 是用于并行执行任务的线程池,特别适合分治算法和递归任务。

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;

class MyRecursiveAction extends RecursiveAction {
    @Override
    protected void compute() {
        // 并行执行的任务
        System.out.println("Thread is running");
    }
}

public class Main {
    public static void main(String[] args) {
        ForkJoinPool pool = new ForkJoinPool();
        MyRecursiveAction task = new MyRecursiveAction();
        pool.invoke(task);
    }
}

8.list.parallelStream()

import java.util.Arrays;
import java.util.List;

public class ParallelStream {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
        list.parallelStream().forEach(System.out::println);
    }

}

parallelStream 是基于 Fork/Join 框架 实现的,它允许将任务拆分成多个子任务并行处理,最后将结果合并。以下是 parallelStream 的底层实现原理:

  1. Fork/Join 框架
    parallelStream 的并行处理依赖于 Java 7 引入的 Fork/Join 框架。该框架的核心思想是:
    分治(Divide and Conquer):将一个大任务拆分成多个小任务(Fork),并行执行这些小任务,最后将结果合并(Join)。
    工作窃取(Work Stealing):每个线程维护一个任务队列,当某个线程完成任务后,可以从其他线程的队列中“窃取”任务来执行,从而提高 CPU 利用率。
  2. 并行流的执行流程
    当调用 parallelStream() 时,Java 会创建一个并行流,其底层执行流程如下:
    (1) 任务拆分
    数据源(如集合)会被拆分成多个子任务。
    拆分的方式取决于数据源的类型:
    对于 ArrayList 等可拆分的数据结构,会按照索引范围拆分成多个子任务。
    对于 HashSet 等不可直接拆分的数据结构,会先转换为数组再进行拆分。
    (2) 并行执行
    每个子任务会被提交到 Fork/Join 线程池(ForkJoinPool.commonPool())中执行。
    默认情况下,线程池的大小为 CPU 核心数 - 1(可以通过 -Djava.util.concurrent.ForkJoinPool.common.parallelism 参数调整)。
    (3) 结果合并
    每个子任务执行完成后,结果会被合并(Join)。
    合并的方式取决于流的操作类型(如 reduce、collect 等)。
  3. 并行流的性能优化
    数据量:并行流适合处理大规模数据,小数据量时串行流(stream())可能更快,因为并行化会引入额外的开销(如任务拆分、线程调度等)。
    数据结构:数据源的结构影响拆分效率。ArrayList 和数组等支持随机访问的数据结构更适合并行流,而 LinkedList 等链表结构则不适合。
    操作类型:某些操作(如 filter、map)适合并行化,而某些操作(如 limit、findFirst)可能会限制并行化的效果。

总结

继承 Thread 类:简单直接,但Java不支持多继承,灵活性较差。

实现 Runnable 接口:更灵活,推荐使用。

实现 Callable 接口:可以返回结果和抛出异常,适合需要返回值的场景。

线程池:高效管理线程资源,适合大量异步任务。

CompletableFuture:支持复杂的异步编程。

Timer 和 TimerTask:适合定时任务。

ForkJoinPool:适合并行计算和分治任务。

根据具体需求选择合适的方式。

相关文章:

  • 阿里云服务器部署项目笔记 实操 centos7.9
  • 《C++ primer》第二章
  • 一、C++上岸教程—C语言基础
  • CentOS 7 IP 地址设置保姆级教程
  • playbin之Source插件加载流程源码剖析
  • 2024_BUAA数据结构上机题解分享
  • 03.03 QT
  • Android开发Android调web的方法
  • Feign 深度解析
  • 火语言RPA--PDF提取表格
  • 详解LSM树
  • matlab 包围盒中心匹配法实现点云粗配准
  • 【Elasticsearch】Set up a data stream 创建data stream
  • AIP-158 分页
  • Leetcode 215 数组中的第K个最大元素
  • 一、计算机等级考试——标准评分
  • Leetcode 37: 解数独
  • 【数据分析】复杂实验,通过正交表组合来进行实验设计
  • 安全渗透测试的全面解析与实践
  • 虚拟机ip配置
  • 著名医学翻译家王贤才逝世,享年91岁
  • 上海环球马术冠军赛开赛,一场体育与假日消费联动的狂欢
  • 挑大梁!一季度北上广等7省份进出口占外贸总值四分之三
  • 五一假期首日,多地党政主官暗访督查节日安全和值班值守工作
  • 超越梅罗,这样一个亚马尔折射巴萨的容错率
  • “五一”假期首日国铁郑州局迎大客流,预计发送旅客逾95万人次