[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

相关文章

使用Java将各种数据写入Excel表格的操作示例

《使用Java将各种数据写入Excel表格的操作示例》在数据处理与管理领域,Excel凭借其强大的功能和广泛的应用,成为了数据存储与展示的重要工具,在Java开发过程中,常常需要将不同类型的数据,本文... 目录前言安装免费Java库1. 写入文本、或数值到 Excel单元格2. 写入数组到 Excel表格

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

Linux之systemV共享内存方式

《Linux之systemV共享内存方式》:本文主要介绍Linux之systemV共享内存方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、工作原理二、系统调用接口1、申请共享内存(一)key的获取(二)共享内存的申请2、将共享内存段连接到进程地址空间3、将

Maven中引入 springboot 相关依赖的方式(最新推荐)

《Maven中引入springboot相关依赖的方式(最新推荐)》:本文主要介绍Maven中引入springboot相关依赖的方式(最新推荐),本文给大家介绍的非常详细,对大家的学习或工作具有... 目录Maven中引入 springboot 相关依赖的方式1. 不使用版本管理(不推荐)2、使用版本管理(推

Java 中的 @SneakyThrows 注解使用方法(简化异常处理的利与弊)

《Java中的@SneakyThrows注解使用方法(简化异常处理的利与弊)》为了简化异常处理,Lombok提供了一个强大的注解@SneakyThrows,本文将详细介绍@SneakyThro... 目录1. @SneakyThrows 简介 1.1 什么是 Lombok?2. @SneakyThrows

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B

如何在 Spring Boot 中实现 FreeMarker 模板

《如何在SpringBoot中实现FreeMarker模板》FreeMarker是一种功能强大、轻量级的模板引擎,用于在Java应用中生成动态文本输出(如HTML、XML、邮件内容等),本文... 目录什么是 FreeMarker 模板?在 Spring Boot 中实现 FreeMarker 模板1. 环

使用Python和Pyecharts创建交互式地图

《使用Python和Pyecharts创建交互式地图》在数据可视化领域,创建交互式地图是一种强大的方式,可以使受众能够以引人入胜且信息丰富的方式探索地理数据,下面我们看看如何使用Python和Pyec... 目录简介Pyecharts 简介创建上海地图代码说明运行结果总结简介在数据可视化领域,创建交互式地

SpringMVC 通过ajax 前后端数据交互的实现方法

《SpringMVC通过ajax前后端数据交互的实现方法》:本文主要介绍SpringMVC通过ajax前后端数据交互的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价... 在前端的开发过程中,经常在html页面通过AJAX进行前后端数据的交互,SpringMVC的controll

Java中的工具类命名方法

《Java中的工具类命名方法》:本文主要介绍Java中的工具类究竟如何命名,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录Java中的工具类究竟如何命名?先来几个例子几种命名方式的比较到底如何命名 ?总结Java中的工具类究竟如何命名?先来几个例子JD