[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

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

计组基础知识

操作系统的特征 并发共享虚拟异步 操作系统的功能 1、资源分配,资源回收硬件资源 CPU、内存、硬盘、I/O设备。2、为应⽤程序提供服务操作系统将硬件资源的操作封装起来,提供相对统⼀的接⼝(系统调⽤)供开发者调⽤。3、管理应⽤程序即控制进程的⽣命周期:进程开始时的环境配置和资源分配、进程结束后的资源回收、进程调度等。4、操作系统内核的功能(1)进程调度能⼒: 管理进程、线