Java 线程创建的方法和原理

创建线程

方法一:Thread 类

创建Thread类的对象,重写其中的 run 方法:

@Slf4j(topic = "c.Test1")
public class d1_Thread {public static void main(String[] args) {// 创建 Thread 类的对象Thread t = new Thread(){@Overridepublic void run(){log.debug("running"); // t1 线程}};t.setName("t1");t.start();log.debug("running"); // main线程}
}

以继承的方式重写 run :

public class MyThread extends Thread{// 2. 重写Thread类的run方法@Overridepublic void run() {// 1. 描述线程的执行任务for (int i = 0; i < 5; i++) {System.out.println("son Thread output : " + i);}}
}public class ThreadTest1 {// main方法由一条默认的主线程负责执行public static void main(String[] args) {// 3. 创建MyThread线程类的对象代表一个线程Thread t = new MyThread();// 4. 启动线程(自动执行 run 方法)t.start();// 已经有两个线程了:main 线程, t线程// 它们这两个线程的输出没有前后for (int i = 0; i < 5; i++) {System.out.println("main Thread output : " + i);}}
}

注意实现:

  1. 启动子线程要调用start方法,而不是run方法,否则还是只有main线程
  2. 子线程任务要放在主线程之前,如果主线程在子线程之前,主线程任务就一定在子线程任务前

缺点:

  • 线程类已经继承了Thread类,无法继承其他类,不利于扩展

方法二:Runnable接口与Thread类

创建Runnable接口的匿名内部类对象,重写其中的 run 方法

/*** Represents an operation that does not return a result.** <p> This is a {@linkplain java.util.function functional interface}* whose functional method is {@link #run()}.** @author  Arthur van Hoff* @see     java.util.concurrent.Callable* @since   1.0*/
@FunctionalInterface
public interface Runnable {/*** Runs this operation.*/void run();
}

其中 Runnable接口只有一个方法,被注解为 FunctionalInterface,所以可以用 lambda表达式简化

@Slf4j(topic = "c.Test2")
public class d2_Runnable {public static void main(String[] args) {
//        Runnable r = new Runnable() {
//            @Override
//            public void run() {
//                log.debug("running");
//            }
//        };// lambda精简代码Runnable r = ()->log.debug("running");Thread t = new Thread(r, "t2");t.start();}
}

以继承接口的方式实现:

// 1. 定义一个任务类,实现Runnable接口
public class MyRunnable implements Runnable{// 2. 重写 Runnable接口的run方法@Overridepublic void run() {// 线程执行的任务for (int i = 0; i < 5; i++) {System.out.println("子线程输出:"+i);}}
}public class ThreadTest2 {public static void main(String[] args) {// 3. 创建任务类的对象Runnable target = new MyRunnable();// 4. 任务对象交给线程对象处理Thread thread = new Thread(target);thread.start();for (int i = 0; i < 5; i++) {System.out.println("主线程执行:" + i);}}
}

优点:任务类只是实现接口,可以继续继承其他类,实现其他接口,扩展性强

实现原理:

Runnable 对象会被赋值给 holder.task 变量,在 Thread 类的 run 方法中会判断是否存在 task 变量,如果存在则优先执行。

直接创建 Thread 对象,对其中的 run方法重写,就等于覆盖了下面的方法。

    @Overridepublic void run() {Runnable task = holder.task;if (task != null) {Object bindings = scopedValueBindings();runWith(bindings, task);}}

方法三:FutureTask接口获取 run 的返回值

实现:

  1. 创建 FutureTask 的对象,传入 Callable参数,泛型选择返回值类型,重写其中的call方法
  2. FutureTask 对象传入 Thread 对象
  3. 调用 FutureTask 对象的 get 方法获取返回值
@Slf4j(topic = "c.Test3")
public class d3_FutureTask {public static void main(String[] args) throws Exception {
//        FutureTask<Integer> task =  new FutureTask<>(new Callable<Integer>() {
//            @Override
//            public Integer call() throws Exception {
//                log.debug("running");
//                Thread.sleep(1000);
//                return 100;
//            }
//        });// 简化:FutureTask<Integer> task = new FutureTask<>(()->{log.debug("running");Thread.sleep(1000);return 100;});new Thread(task, "t3").start();Integer result = task.get();log.debug("result = {}", result);}
}

以继承Callable接口的方式实现:

public class MyCallable implements Callable<String> {private int n;public MyCallable(int n) {this.n = n;}@Overridepublic String call() throws Exception {// 描述线程任务,返回线程执行结果int sum = 0;for(int i = 1; i <= n; ++ i){sum += i;}return "线程求出了1-"+ n + "的和是:"+sum;}
}public class ThreadTest3 {public static void main(String[] args) throws Exception {// 前两次重写run方法在不同线程中执行代码无法返回数据// Callable接口,FutureTask类的实现,可以直接返回数据// 创建一个重写了Callable接口的对象Callable<String> call = new MyCallable(100);// Callable的对象封装为FutureTask的对象FutureTask<String> f1 = new FutureTask<>(call);// 作用:// 1.任务对象,实现了Runnable接口// 2. 线程执行饭毕后可以调用get方法获取线程执行完毕后的结果new Thread(f1).start();Callable<String> call2 = new MyCallable(200);FutureTask<String> f2 = new FutureTask<>(call2);new Thread(f2).start();// 获取线程执行完毕后的结果.// get获取的返回结果就是call方法返回的结果// call返回的结果可能是符合返回类型的或者不符合,所有这里有异常,需要抛出System.out.println(f1.get());System.out.println(f2.get());// 如果上面的线程代码没有执行完毕,这里的f1.get方法会暂停,等待上面代码执行完毕才会获取结果}
}

实现原理(继承关系):

  1. 首先 FutureTask 实现了 RunnableFuture 接口
    • RunnableFuture 接口是由 RunnableFuture<V> 接口组成的
    • 实现了 Runnable 接口的 run 方法
    • 实现了 Future<V> 接口的 get 方法
  2. FutureTaskrun 中的实现:
    1. 获取 callable对象
    2. 调用 callable对象中的 call 方法
    3. 等待 call 方法执行完成,获取返回值并赋值给 result
  3. callable 对象的获取是通过 FutureTask的构造函数传入的
  4. 调用实现的 get 方法获取 call方法的返回值 result
    1. set方法将 result -> outcome
    2. get方法调用 report方法获取outcome
// 1. FutureTask实现了RunnableFuture接口
public class FutureTask<V> implements RunnableFuture<V>// RunnableFuture接口 继承了 Runnable
public interface RunnableFuture<V> extends Runnable, Future<V> {/*** Sets this Future to the result of its computation* unless it has been cancelled.*/void run();
}// RunnableFuture接口 继承了 Future<V>接口
// get 方法可以获取返回值
public interface Future<V> {// ...V get() throws InterruptedException, ExecutionException;// ...V get(long timeout, TimeUnit unit)throws InterruptedException, ExecutionException, TimeoutException;// ...
}// 2. FutrureTask类中对 run 方法的具体实现:
public void run() {if (state != NEW ||!RUNNER.compareAndSet(this, null, Thread.currentThread()))return;try {Callable<V> c = callable;   // 2.1. 获得一个 callable对象if (c != null && state == NEW) {V result;boolean ran;try {result = c.call();	// 2.2. 调用 callable对象中的 call 方法(call方法一般由用户重写)ran = true;} catch (Throwable ex) {result = null;ran = false;setException(ex);}if (ran)set(result); // 2.3. 如果 call 方法执行完毕,则将返回值赋值给result}} finally {// runner must be non-null until state is settled to// prevent concurrent calls to run()runner = null;// state must be re-read after nulling runner to prevent// leaked interruptsint s = state;if (s >= INTERRUPTING)handlePossibleCancellationInterrupt(s);}}
// 3. FutureTask的构造方法,传入了 Callable 接口对象
public FutureTask(Callable<V> callable) {if (callable == null)throw new NullPointerException();this.callable = callable;this.state = NEW;       // ensure visibility of callable
}// set 方法将 result 结果赋值给 outcome
protected void set(V v) {if (STATE.compareAndSet(this, NEW, COMPLETING)) {outcome = v;STATE.setRelease(this, NORMAL); // final statefinishCompletion();}
}
// report 方法返回 outcome 结果
private V report(int s) throws ExecutionException {Object x = outcome;if (s == NORMAL)return (V)x;if (s >= CANCELLED)throw new CancellationException();throw new ExecutionException((Throwable)x);
}
// get方法 返回 report中的outcom结果
public V get() throws InterruptedException, ExecutionException {int s = state;if (s <= COMPLETING)s = awaitDone(false, 0L);return report(s);
}

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

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

相关文章

SQL进阶理论篇(六):索引的使用原则

文章目录 简介什么时候创建索引&#xff1f;什么时候不需要创建索引索引在什么情况下会失效索引使用举例&#xff08;兴趣篇&#xff09;参考文献 简介 如何通过索引让查询效率最大化呢&#xff1f;本节主要考虑以下几个问题&#xff1a; 什么样的情况下需要创建索引&#xf…

C++中的reverse函数

1.实现反转数组。 //头文件 #include <algorithm> //使用方法 reverse(a, an);//n为数组中的元素个数 #include<cstdio> #include<iostream> #include<algorithm> using namespace std; int main() {int a[100];int n,k;cin >> n >> k; …

基于SpringBoot的停车位预约管理系统

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于SpringBoot的停车位预约管理系统,ja…

八大排序(插入排序 | 选择排序 | 冒泡排序)

在我们内存中我们一般会有一些没有顺序的数据&#xff0c;我们成为内排序&#xff0c;而今天分享八大排序的是时间复杂度为O&#xff08;N^2&#xff09;的插入排序&#xff0c;选择排序和教学意义比较强的冒泡排序。 插入排序 这是插入排序的动图&#xff0c;通过动图我们也…

PHP中如何处理文件上传?

在 PHP 中处理文件上传通常涉及到以下几个步骤&#xff1a; HTML 表单设置&#xff1a; 在 HTML 表单中设置 enctype 属性为 "multipart/form-data"&#xff0c;这是处理文件上传所必须的。 <form action"upload.php" method"post" enctype&q…

Python3 中常见的数据类型

目录 数字(Number)总结 字符串(String)字符串运算符字符串格式化字符串的截取总结 List&#xff08;列表&#xff09;更新列表删除列表元素列表函数&方法总结 Tuple&#xff08;元组&#xff09;修改元组删除元组总结 Set&#xff08;集合&#xff09;Dictionary&#xff0…

重新格式化字符串

说在前面 &#x1f388;不知道大家对于算法的学习是一个怎样的心态呢&#xff1f;为了面试还是因为兴趣&#xff1f;不管是出于什么原因&#xff0c;算法学习需要持续保持。 题目描述 给你一个混合了数字和字母的字符串 s&#xff0c;其中的字母均为小写英文字母。 请你将该字…

npm、yarn常用命令

1、设置npm路径 #全局安装路径 npm config set prefix "D:\Program Files\nodejs\node_global" #缓存路径 npm config set cache "D:\Program Files\nodejs\node_cache"2、设置镜像 #1,淘宝镜像源 npm config set registry https://registry.npmmirror.…

3D点云广义零样本分类的递归循环对比生成网络笔记

1 Title Contrastive Generative Network with Recursive-Loop for 3D point cloud generalized zero-shot classification(Yun Hao, Yukun Su, Guosheng Lin, Hanjing Su, Qingyao Wu)【Pattern Recognition】 2 Conclusion This work aims to facilitate research on 3D poi…

【Spring Boot】内网穿透实现远程调用调试

文章目录 1. 本地环境搭建1.1 环境参数1.2 搭建springboot服务项目 2. 内网穿透2.1 安装配置cpolar内网穿透2.1.1 windows系统2.1.2 linux系统 2.2 创建隧道映射本地端口2.3 测试公网地址 3. 固定公网地址3.1 保留一个二级子域名3.2 配置二级子域名3.2 测试使用固定公网地址 4.…

机器学习入门笔记

文章目录 背景具体步骤1.环境搭建2.写个demo1.数据处理2.分割数据集3.用模型训练数据&#xff0c;并得到预测结果4.绘制结果5.评估 背景 最近学习了一些关于机器学习的内容&#xff0c;做个笔记。 具体步骤 1.环境搭建 需要用到的工具&#xff1a;pycharm&#xff0c;anaco…

如何了解蜘蛛池蚂蚁SEO

蜘蛛池是一种基于搜索引擎优化的技术手段&#xff0c;通过模拟蜘蛛爬行行为来提高网站在搜索引擎中的排名&#xff0c;从而增加网站的流量和曝光率。 编辑搜图 如何联系蚂蚁seo&#xff1f; baidu搜索&#xff1a;如何联系蚂蚁SEO&#xff1f; baidu搜索&#xff1a;如何联…

【Pytorch】Fizz Buzz

文章目录 1 数据编码2 网络搭建3 网络配置&#xff0c;训练4 结果预测5 翻车现场 学习参考来自&#xff1a; Fizz Buzz in Tensorflowhttps://github.com/wmn7/ML_Practice/tree/master/2019_06_10Fizz Buzz in Pytorch I need you to print the numbers from 1 to 100, excep…

pdf读取内容缺失(漏字/文字丢失)问题

项目中遇到pdf文件漏字&#xff0c;由于文件涉密&#xff0c;不能展示&#xff0c;简单描述一下&#xff1a; 比如原pff中 姓名&#xff1a;张三 读取结果中&#xff1a;空白&#xff1a;张三 即&#xff1a;原文件说是银行出具的打款证明&#xff0c;银行内部设置了文件权限&a…

读取excel写入数据库

String filePath “C:\Users\Farben\Desktop\地图助残.xlsx”; ReadExcel readExcel new ReadExcel(); // System.out.println(readExcel(filePath).toString()); // 存放读取出来的姓名和电话 InputStream iStream new FileInputStream(filePath); XSSFWorkbook workbook …

牛客网BC92逆序输出

答案&#xff1a; #include <stdio.h>int main() {int i0, j0;int arr[10]{0};for(i0;i<10;i) //将10个整数存进数组里{scanf("%d",&arr[i]);}for(j9;j>0;j--) //逆序打印{printf("%d ",arr[j]); //若要求最后一个数后面不打印空格…

【Hive】——CLI客户端(bin/beeline,bin/hive)

1 HiveServer、HiveServer2 2 bin/hive 、bin/beeline 区别 3 bin/hive 客户端 hive-site.xml 配置远程 MateStore 地址 XML <?xml version"1.0" encoding"UTF-8" standalone"no"?> <?xml-stylesheet type"text/xsl" hre…

C# WPF上位机开发(利用tcp/ip网络访问plc)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 c# wpf如果是用来开发非标上位机的&#xff0c;那么和plc的通信肯定是少不了的。而且&#xff0c;大部分plc都支持modbus协议&#xff0c;所以这个…

neo4j安装报错:neo4j.bat : 无法将“neo4j.bat”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。

neo4j安装报错&#xff1a; neo4j.bat : 无法将“neo4j.bat”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写&#xff0c;如果包括路径&#xff0c;请确 保路径正确&#xff0c;然后再试一次。 解决办法&#xff1a; 在环境变量中的&#xff0c;用户…

Shopee ERP:提升电商管理效率的终极解决方案

Shopee ERP&#xff08;Enterprise Resource Planning&#xff0c;企业资源规划&#xff09;是一款专为Shopee卖家设计的集成化电商管理软件。通过使用Shopee ERP系统&#xff0c;卖家可以更高效地管理他们的在线商店&#xff0c;实现库存管理、订单处理、物流跟踪、财务管理、…