[JAVA基础知识汇总-1] 创建线程的几种方式

news2025/1/4 15:54:36

文章目录

  • 1. 继承Thread类
  • 2. 实现Runnable接口
  • 3. 实现Callable接口
  • 4. 线程池

可以认为有四种方式,也可以认为有一种,因为都跟Runnable接口有关

1. 继承Thread类

代码

public class Thread1ExtendsThread extends Thread {
//    public Thread1(String name) {
//        super(name);
//    }

    @Override

    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println("这里是自定义线程:" + Thread.currentThread().getName() + ", i = " + i + ";");
        }
    }

    public static void main(String[] args) {
        // new Thread1("xinliushijian").start();
        new Thread1ExtendsThread().start();
        for (int i = 0; i < 3; i++) {
            System.out.println("这里是main线程:" + Thread.currentThread().getName() + ", i = " + i + ";");
        }
    }
}

打印

这里是main线程:main, i = 0;
这里是main线程:main, i = 1;
这里是main线程:main, i = 2;
这里是自定义线程:Thread-0, i = 0;
这里是自定义线程:Thread-0, i = 1;
这里是自定义线程:Thread-0, i = 2;

知识点

  1. new Thread 构造器的参数可以是Runnable,但没有Callable,因为如果是实现了Callable接口的线程,参数应该是FutureTask
  2. Thread 是Runnable接口的实现类
  3. 这种方式的坏处是不能再继承其他类了,因为java是单继承
  4. 没有返回值

在这里插入图片描述

2. 实现Runnable接口

代码

public class Thread2Runnable implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println("这里是自定义线程:" + Thread.currentThread().getName() + ", i = " + i + ";");
        }
    }

    public static void main(String[] args) {
        Thread2Runnable thread2 = new Thread2Runnable();
        new Thread(thread2).start();
        for (int i = 0; i < 3; i++) {
            System.out.println("这里是main线程:" + Thread.currentThread().getName() + ", i = " + i + ";");
        }
    }
}

打印

这里是main线程:main, i = 0;
这里是main线程:main, i = 1;
这里是main线程:main, i = 2;
这里是自定义线程:Thread-0, i = 0;
这里是自定义线程:Thread-0, i = 1;
这里是自定义线程:Thread-0, i = 2;

知识点

  1. 没有返回值

3. 实现Callable接口

代码

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

public class Thread3Callable implements Callable {

    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 0; i < 3; i++) {
            sum += i;
            System.out.println("这里是自定义线程:" + Thread.currentThread().getName() + ", i = " + i + ";");
        }
        return sum;
    }

    public static void main(String[] args) {
        // 使用Lambda表达式创建Callable对象, FutureTask类来包装Callable对象
//        FutureTask<Integer> future = new FutureTask<>(
//                () -> 3
//        );
        FutureTask<Integer> future = new FutureTask<>(new Thread3Callable());
        // 实质上还是以Callable对象来创建并启动线程
        new Thread(future).start();
        try {
            // get()方法会阻塞,直到子线程执行结束才返回
            System.out.println("自定义线程返回值:" + future.get());
        } catch (Exception e) {
            e.printStackTrace();
        }

        for (int i = 0; i < 3; i++) {
            System.out.println("这里是main线程:" + Thread.currentThread().getName() + ", i = " + i + ";");
        }
    }
}

打印

这里是自定义线程:Thread-0, i = 0;
这里是自定义线程:Thread-0, i = 1;
这里是自定义线程:Thread-0, i = 2;
自定义线程返回值:3
这里是main线程:main, i = 0;
这里是main线程:main, i = 1;
这里是main线程:main, i = 2;

知识点

  1. 有返回值,需要跟FutureTask搭配使用,来获得线程的执行结果
  2. FutureTask也是实现了Runnable接口
  3. 以上三种方式都是new Thread().start()的方式去启动线程
    在这里插入图片描述

4. 线程池

  1. 利用Executors工具类来创建线程池

代码

import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

public class ThreadDemo3Executors {
    public static void main(String[] args) {
        // 创建线程工厂
        ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("Async-pool-%d").build();

        // 创建定时任务的线程池
        Executors.newScheduledThreadPool(4, threadFactory);

        // 创建可缓存的线程池,只会重用空闲可用的线程,没有可用的线程时会创建新线程
        Executors.newCachedThreadPool();

        // 单个线程的线程池
        Executors.newSingleThreadExecutor();

        // 固定线程数量的线程池
        Executors.newFixedThreadPool(3);
    }
}
  1. ThreadPoolExecutor是线程池的核心实现类,可以利用它来创建线程池

在这里插入图片描述

Executor线程池相关顶级接口,它将任务的提交与任务的执行分离开来
ExecutorService继承并扩展了Executor接口,提供了Runnable、FutureTask等主要线程实现接口扩展
ThreadPoolExecutor是线程池的核心实现类,用来执行被提交的任务
ScheduledExecutorService继承ExecutorService接口,并定义延迟或定期执行的方法
ScheduledThreadPoolExecutor继承ThreadPoolExecutor并实现了ScheduledExecutorService接口,是延时执行类任务的主要实现

源码

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

ThreadPoolExecutor包含了7个核心参数,参数含义:

corePoolSize:核心线程数
maximumPoolSize:最大线程数
keepAliveTime:当线程池中线程数大于corePoolSize,并且没有可执行任务时大于corePoolSize那部分线程的存活时间
unit:keepAliveTime的时间单位
workQueue:用来暂时保存任务的工作队列
threadFactory:线程工厂提供线程的创建方式,默认使用Executors.defaultThreadFactory()
handler:当线程池所处理的任务数超过其承载容量或关闭后继续有任务提交时,所调用的拒绝策略

代码

import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadDemo4ThreadPoolExecutor {

    public static final ThreadPoolExecutor EXECUTOR_SERVICE;
    static {
        int corePoolSize = 500;
        int maxPoolSize = 500;
        ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("xinliushijian-thread-pool-%d").build();
        RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                if (!executor.isShutdown()) {
                    try {
                        executor.getQueue().put(r);
                    } catch (InterruptedException e) {
                        System.out.println("hahaha");
                    }

                }
            }
        };

        EXECUTOR_SERVICE = new ThreadPoolExecutor(corePoolSize, maxPoolSize, 0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue(), threadFactory, rejectedExecutionHandler);
    }

    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName());
        List<String> nameList = new ArrayList<>();
        List<String> nameResultList = new ArrayList<>();
        nameList.add("xiaohua");
        nameList.add("xiaohua1");
        nameList.add("xiaohua2");
        nameList.add("xiaohua3");
        nameList.add("xiaohua4");
        nameList.add("xiaohua5");
        nameList.add("xiaohua6");
        nameList.add("xiaohua7");
        CountDownLatch countDownLatch = new CountDownLatch(nameList.size());
        nameList.forEach(name -> {
            dealWithName(name, countDownLatch, nameResultList);
        });

        System.out.println("nameResultList前: " + nameResultList);

        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            System.out.println("exception");
        }

        System.out.println("nameResultList后: " + nameResultList);
    }

    private static void dealWithName(String name, CountDownLatch countDownLatch, List<String> nameResultList) {
        EXECUTOR_SERVICE.execute(() -> {
            countDownLatch.countDown();
            System.out.println(name + "haha");
            System.out.println(Thread.currentThread().getName());
            // 打印当前线程数
            System.out.println("打印当前线程数: " + EXECUTOR_SERVICE.getPoolSize());

            // 打印执行任务的线程数
            System.out.println("打印执行任务的线程数: " + EXECUTOR_SERVICE.getActiveCount());

            // 总任务数 = 正在执行的任务数 + 队列任务数
            System.out.println("总任务数 = 正在执行的任务数 + 队列任务数: " + EXECUTOR_SERVICE.getTaskCount());

            nameResultList.add(name);
        });
    }
}

打印

main
xiaohuahaha
xinliushijian-thread-pool-0
xiaohua1haha
xinliushijian-thread-pool-1
打印当前线程数: 3
xiaohua3haha
xinliushijian-thread-pool-3
xiaohua2haha
xinliushijian-thread-pool-2
打印当前线程数: 5
打印当前线程数: 4
打印执行任务的线程数: 6
打印当前线程数: 5
总任务数 = 正在执行的任务数 + 队列任务数: 6
xiaohua5haha
xinliushijian-thread-pool-5
打印当前线程数: 7
打印执行任务的线程数: 6
总任务数 = 正在执行的任务数 + 队列任务数: 8
xiaohua6haha
xinliushijian-thread-pool-6
打印当前线程数: 8
打印执行任务的线程数: 6
总任务数 = 正在执行的任务数 + 队列任务数: 8
打印执行任务的线程数: 5
xiaohua7haha
xinliushijian-thread-pool-7
打印当前线程数: 8
nameResultList前: [xiaohua2, xiaohua5]
打印执行任务的线程数: 6
总任务数 = 正在执行的任务数 + 队列任务数: 8
打印执行任务的线程数: 6
打印执行任务的线程数: 5
总任务数 = 正在执行的任务数 + 队列任务数: 8
总任务数 = 正在执行的任务数 + 队列任务数: 8
总任务数 = 正在执行的任务数 + 队列任务数: 8
xiaohua4haha
xinliushijian-thread-pool-4
nameResultList后: [xiaohua2, xiaohua5, xiaohua6, xiaohua3, xiaohua, xiaohua7, xiaohua1]
打印当前线程数: 8
打印执行任务的线程数: 1
总任务数 = 正在执行的任务数 + 队列任务数: 8

源码

ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("xinliushijian-thread-pool-%d").build();
public ThreadFactory build() {
    return doBuild(this);
}
private static ThreadFactory doBuild(ThreadFactoryBuilder builder) {
        final String nameFormat = builder.nameFormat;
        final Boolean daemon = builder.daemon;
        final Integer priority = builder.priority;
        final Thread.UncaughtExceptionHandler uncaughtExceptionHandler = builder.uncaughtExceptionHandler;
        final ThreadFactory backingThreadFactory = builder.backingThreadFactory != null ? builder.backingThreadFactory : Executors.defaultThreadFactory();
        final AtomicLong count = nameFormat != null ? new AtomicLong(0L) : null;
        return new ThreadFactory() {
            public Thread newThread(Runnable runnable) {
                Thread thread = backingThreadFactory.newThread(runnable);
                Objects.requireNonNull(thread);
                if (nameFormat != null) {
                    thread.setName(ThreadFactoryBuilder.format(nameFormat, ((AtomicLong)Objects.requireNonNull(count)).getAndIncrement()));
                }

                if (daemon != null) {
                    thread.setDaemon(daemon);
                }

                if (priority != null) {
                    thread.setPriority(priority);
                }

                if (uncaughtExceptionHandler != null) {
                    thread.setUncaughtExceptionHandler(uncaughtExceptionHandler);
                }

                return thread;
            }
        };
    }
    public interface ThreadFactory {

    /**
     * Constructs a new {@code Thread}.  Implementations may also initialize
     * priority, name, daemon status, {@code ThreadGroup}, etc.
     *
     * @param r a runnable to be executed by new thread instance
     * @return constructed thread, or {@code null} if the request to
     *         create a thread is rejected
     */
    Thread newThread(Runnable r);
}

知识点

从上面源码可以清楚看到,其中创建线程的步骤在ThreadFactory,线程工厂创建的线程是实现了Runnable接口,所以利用线程池来创建线程也是跟Runnable有关,所以这四种创建线程的方式其实都跟Runnable有关。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2112987.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

思维导图与头脑风暴:你值得拥有的四大工作与学习利器

在工作与学习中&#xff0c;我们都遇到过这样的情况&#xff1a;我们需要就某一问题或项目&#xff0c;汇集多人的智慧与创意&#xff0c;这时&#xff0c;头脑风暴便成为了我们不可或缺的利器&#xff1b;而为了更好地进行头脑风暴&#xff0c;选择一款合适的在线思维导图工具…

【Qt开发】QT6.5.3安装方法(使用国内源)亲测可行!!!

目录 &#x1f315;下载在线安装包&#x1f315; 把安装包放到系统盘&#x1f315;开始安装&#x1f315;参考文章 &#x1f315;下载在线安装包 https://mirrors.nju.edu.cn/qt/official_releases/online_installers/ &#x1f315; 把安装包放到系统盘 我的系统盘是G盘&…

uniapp 全屏日历,动态无限加载

不好用请移至评论区揍我 原创代码,请勿转载,谢谢! 注:本人仅在微信小程序测试过,未在其他app/h5尝试过,按理说应该是可以的,代码没有引用任何第三方组件 日历中每个日期下方的空白部分均可自定义,写在代码中的<view class="item">我是内容</view>…

Go入门指南(The Way to Go) 完整版PDF

The Way To Go可以说是入门 Go 的经典书籍&#xff0c;这本书有内容丰富各种资料链接&#xff0c;这是截止到目前&#xff0c;大叔看到的写得最好的go 语言教材&#xff0c;非常详细.一口气读下来&#xff0c;舍不得放手&#xff0c;大叔强烈推荐你去学习 百度网盘分享

docker基于minio部署outline团队知识库

outline 介绍 Outline 是一个开源的Wiki 知识库和团队协作文档管理工具&#xff0c;美观、实时协作、功能丰富且兼容 Markdown&#xff0c;设计用于帮助团队和组织有效地创建、共享和管理文档。 Outline 具有简单易用的界面和强大的功能&#xff0c;可以替代传统的文档管理系…

winndows系统修改cmd用户中文名、系统中文用户名修改为英文用户名的方法

文章目录 一、问题描述二、修改步骤1. 准备&#xff1a;2. 注销&#xff1a;3. 修改&#xff1a;4. 继续修改&#xff1a; 一、问题描述 电脑用户显示中文名&#xff08;我这里已经修改了&#xff09; 二、修改步骤 1. 准备&#xff1a; 我们需要使用 Administrator 登录&am…

OpenGL——画一个填充的三角形

1. vertShader.glsl&#xff08;顶点着色器代码&#xff09;&#xff1a; #version 460void main (void) {if (gl_VertexID 0)gl_Position vec4 (0.25, -0.25, 0.0, 1.0);else if (gl_VertexID 1)gl_Position vec4 (-0.25, -0.25, 0.0, 1.0);elsegl_Position vec4 (0.25,…

[C/C++入门][进制原理]31、求分数序列和

题目来自于信息学奥赛 1078 分析&#xff1a; 这道题看起来比较复杂&#xff0c;实际上只需要通过两个公式&#xff0c;一次性求出分母和分子&#xff0c;然后把这个求出来的数加入到变量和中。甚至都不需要知道总共游哪些数。数组都用不上。循环就能解决。 #include <ios…

快速排序(QuickSort)-归并排序(MergeSort)[java编写]

1. 快速排序 1.1 基本概述 快速排序采用分治思想&#xff0c;即在一个无序的序列中选取一个任意的基准元素pivot&#xff0c;利用pivot 将待排序的序列分成两部分&#xff0c;前面部分元素均小于或等于基准元素&#xff0c;后面部分均大于或等于基准元素&#xff0c;然后采用…

Chapter 10 Stability and Frequency Compensation

Chapter 10 Stability and Frequency Compensation Chapter 8介绍了负反馈, 这一章介绍稳定性, 如果设计不好, 负反馈系统是要发生震荡的. 首先我们学习理解稳定判断标准和条件, 然后学习频率补偿, 介绍适用于不同运放的补偿方式, 同时介绍不同补偿对两级运放slew rate的影响…

2024全新苹果cms影视源码/仿韩剧TV主题模板源码/电影视频在线观看网站源码-自适应 (PC+WAP)

源码简介 2024年最新版的苹果CMS影视源码&#xff0c;仿制了韩剧TV的主题模板&#xff0c;让网站看起来跟韩剧TV一模一样&#xff0c;而且这个源码支持在线观看电影和视频&#xff0c;无论是在电脑&#xff08;PC&#xff09;还是手机&#xff08;WAP&#xff09;上都能完美自…

网络编程之-UDP详解

&#x1f308;个人主页&#xff1a;努力学编程’ ⛅个人推荐&#xff1a; c语言从初阶到进阶 JavaEE详解 数据结构 ⚡学好数据结构&#xff0c;刷题刻不容缓&#xff1a;点击一起刷题 &#x1f319;心灵鸡汤&#xff1a;总有人要赢&#xff0c;为什么不能是我呢 &#x1f3c0…

2024年 Biomedical Signal Processing and Control 期刊投稿经验最新分享

期刊介绍 《Biomedical Signal Processing and Control 》期刊旨在为临床医学和生物科学中信号和图像的测量和分析研究提供一个跨学科的国际论坛。重点放在处理在临床诊断&#xff0c;患者监测和管理中使用的方法和设备的实际&#xff0c;应用为主导的研究的贡献。 生物医学信…

【大模型基础】P1 N-Gram 模型

目录 N-Gram 概述N-Gram 构建过程TokenN-Gram 实例第1步 构建实验语料库第2步 把句子分成 N 个 “Gram”第3步 计算每个 Bigram 在语料库中的词频第4步 计算出现的概率第5步 生成下一个词第6步&#xff1a;输入前缀&#xff0c;生成连续文本 上述实例完整代码N-Gram 的局限性 N…

一文理解粒子滤波

0. 粒子滤波流程 之前学习记录的文档&#xff0c;这里也拿出来分享一下~ 基本原理&#xff1a;随机选取预测域的 N NN 个点&#xff0c;称为粒子。以此计算出预测值&#xff0c;并算出在测量域的概率&#xff0c;即权重&#xff0c;加权平均就是最优估计。之后按权重比例&…

揭秘帕金森症幕后元凶:是哪些因素悄悄“震颤”了生活?

在这个快节奏的时代&#xff0c;健康成为了我们最宝贵的财富之一。然而&#xff0c;有一种名为“帕金森病”的神秘疾病&#xff0c;正悄悄影响着无数人的生活&#xff0c;让他们的日常充满了“不由自主”的颤抖。今天&#xff0c;就让我们一起揭开帕金森症的神秘面纱&#xff0…

【电路笔记】-同相运算放大器

同相运算放大器 文章目录 同相运算放大器1、概述2、理想的同相运算放大器3、实际同相运算放大器3.1 闭环增益3.2 输出阻抗3.3 输入阻抗4、同相运算放大器示例4.1 缓冲电路4.2 示例5、总结1、概述 施加到运算放大器的电压信号可以提供给其同相输入端 (+) 或反相输入端 (-)。 这…

ansible--role

简介 roles是ansible&#xff0c;playbooks的目录的组织结构&#xff0c;将代码或文件进行模块化&#xff0c;成为roles的文件目录组织结构。 易读&#xff0c;代码可冲哟美好&#xff0c;层次清晰 目录机构 mkdir roles/nginx/{files,handlers,tasks,templates,vars} -ptou…

LLM模型:代码讲解Transformer运行原理

视频讲解、获取源码&#xff1a;LLM模型&#xff1a;代码讲解Transformer运行原理(1)_哔哩哔哩_bilibili 1 训练保存模型文件 2 模型推理 3 推理代码 import torch import tiktoken from wutenglan_model import WutenglanModelimport pyttsx3# 设置设备为CUDA&#xff08;如果…

javaWeb【day04】--(MavenSpringBootWeb入门)

01. Maven课程介绍 1.1 课程安排 学习完前端Web开发技术后&#xff0c;我们即将开始学习后端Web开发技术。做为一名Java开发工程师&#xff0c;后端Web开发技术是我们学习的重点。 1.2 初识Maven 1.2.1 什么是Maven Maven是Apache旗下的一个开源项目&#xff0c;是一款用于…