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

2024-09-07 18:36

本文主要是介绍[JAVA基础知识汇总-1] 创建线程的几种方式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

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

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

1. 继承Thread类

代码

public class Thread1ExtendsThread extends Thread {
//    public Thread1(String name) {
//        super(name);
//    }@Overridepublic 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{@Overridepublic 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 {@Overridepublic 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() {@Overridepublic 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有关。

这篇关于[JAVA基础知识汇总-1] 创建线程的几种方式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1145836

相关文章

Debezium 与 Apache Kafka 的集成方式步骤详解

《Debezium与ApacheKafka的集成方式步骤详解》本文详细介绍了如何将Debezium与ApacheKafka集成,包括集成概述、步骤、注意事项等,通过KafkaConnect,D... 目录一、集成概述二、集成步骤1. 准备 Kafka 环境2. 配置 Kafka Connect3. 安装 D

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

Spring AI集成DeepSeek的详细步骤

《SpringAI集成DeepSeek的详细步骤》DeepSeek作为一款卓越的国产AI模型,越来越多的公司考虑在自己的应用中集成,对于Java应用来说,我们可以借助SpringAI集成DeepSe... 目录DeepSeek 介绍Spring AI 是什么?1、环境准备2、构建项目2.1、pom依赖2.2

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

Spring Cloud LoadBalancer 负载均衡详解

《SpringCloudLoadBalancer负载均衡详解》本文介绍了如何在SpringCloud中使用SpringCloudLoadBalancer实现客户端负载均衡,并详细讲解了轮询策略和... 目录1. 在 idea 上运行多个服务2. 问题引入3. 负载均衡4. Spring Cloud Load

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录