Java多线程基础概述

news/2024/11/16 19:40:33/

 简述多线程:

是指从软件或者硬件上实现多个线程并发执行的技术。
具有多线程能力的计算机因有硬件支持而能够在同一时间执行多个线程,提升性能。

正式着手代码前,需要先理清4个概念:并发,并行,进程,线程

1.并发:

可以理解为在同一时刻,有多个指令在单核CPU上交替执行。单核cpu就好比一条赛道,赛车就好比指令,第一名才有资格使用cpu的资源,所以在单核cpu中指令的并发就像赛车的缠斗,互相抢夺第一名来使用cpu的资源。

 2.并行:

在同一时刻,有多个指令在多个CPU上同时执行。并行的前提是cpu资源充足,在多核cpu中可以实现并行,就像车道来到了多车道宽敞的公路,不比再过分争夺资源,可以同时悠闲的进行多个指令。

总结一下:

并行:在同一时刻,有多个指令在多个CPU上同时执行。

并发:在同一时刻,有多个指令在单个CPU上交替执行。

3.进程:

是正在运行的软件。手机中的APP,电脑中的C/S系统,都可以看做一个进程,用上面的例子中的标注,一台摩托车就可以看做一个进程。规范些的描述如下:

独立性: 进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位。

动态性: 进程的实质是程序的一次执行过程,进程是动态产生,动态消亡的。

并发性:任何进程都可以同其他进程一起并发执行。

4.线程:

是进程中的单个顺序控制流,是一条执行路径。就好比手机App中的一条下单或者退款指令,或者电脑中的一次点击提交操作。相对进程是部分性的存在,在进程中独立运行,用上述例子就好比摩托车中的发动机活塞往复。

 言归正传,下面列举下多线程的实现方式:

继承Thread类的方式进行实现

实现Runnable接口的方式进行实现

利用Callable和Future接口方式实现


 1.继承Thread类方式的基础实现:

package com.demo;public class ThreadDemo extends Thread{@Overridepublic void run(){super.run();System.out.println("第一段线程");}public static void main(String[] args) {ThreadDemo threadDemo = new ThreadDemo();threadDemo.start();}
}


样例继承Thread类后重写run()方法,然后再main方法中new一个样例出来,通过执行Thread类自带的start()方法运行后即可实现程序的运行。执行结果可见:
在这里插入图片描述

这里注意两个地方:

(1)为什么要重写run()方法?

因为run()是用来封装被线程执行的代码,也就是我们在使用时需要将业务逻辑写在run方法中。

(2)run()方法和start()方法的区别?

run():封装线程执行的代码,直接调用,相当于普通方法的调用,并没有开启线程。

start():启动线程;然后由JVM调用此线程的run()方法


 2.实现Runnable接口方式:

package com.demo;public class RunableDemo implements Runnable {@Overridepublic void run(){System.out.println("RUNABLE线程");}public static void main(String[] args) {//runable是个接口,没有start方法去执行,需要借助thread类RunableDemo runableDemo = new RunableDemo();Thread thread = new Thread(runableDemo);thread.start();}
}


这里的Runnable接口不是一个类,没有自带的start()方式,所以在执行时需要借助Thread类,将样例以参数的形式传入来实现执行,thread类自带的tread方法如下:
参数定义了Runnable类型的入参
该方式运行结果:

在这里插入图片描述
3.实现Callable接口方式:

public static class MyCallable implements Callable<String> {@Overridepublic String call() throws Exception {for (int i = 0; i < 10; i++) {System.out.println("超车" + i);}//返回值就表示线程运行完毕之后的结果return "获胜";}}public static void main(String[] args) throws ExecutionException, InterruptedException {//线程开启之后需要执行里面的call方法MyCallable mc = new MyCallable();//Thread t1 = new Thread(mc);//可以获取线程执行完毕之后的结果.也可以作为参数传递给Thread对象FutureTask<String> ft = new FutureTask<>(mc);//创建线程对象Thread t1 = new Thread(ft);//开启线程t1.start();String s = ft.get();System.out.println(s);}

因为thread中只能传入rannable接口,所以callable接口在实现时需要借助FutureTask类,该类的类关系图中可知,最终是继承了rannable,所以可以在thread中使用。

 具体实现步骤如下:

 定义一个类MyCallable实现Callable接口

在MyCallable类中重写call()方法,这里call()方法就是替代上面的run()方法,callable没有run()方法

创建MyCallable类的对象

创建Future的实现类FutureTask对象,把MyCallable对象作为构造方法的参数

创建Thread类的对象,把FutureTask对象作为构造方法的参数,即call()方法返回的数据, 启动线程 再调用get方法,就可以获取线程结束之后的结果。


执行程序结果如下:

 三种方式对比:


以上就是3种基本的多线程最简单的实现方式,简单到底了。

除了最简单的实现方式外,还有一些关于线程的参数设置规则:

1.设置,获取线程的名字,线程休眠

代码演示如下,这里用threa类为例:

 public static class ThreadDemo extends Thread {
//        public ThreadDemo(String name) {
//            super(name);
//        }@Overridepublic void run() {super.run();for (int i = 0; i < 15; i++) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(getName() + "超车---积分" + i);}}public static void main(String[] args) throws ExecutionException, InterruptedException {
//            ThreadDemo yamaha = new ThreadDemo("雅马哈");
//            ThreadDemo honda = new ThreadDemo("本田");ThreadDemo yamaha = new ThreadDemo();ThreadDemo honda = new ThreadDemo();yamaha.setName("雅马哈");honda.setName("本田");yamaha.start();honda.start();
}

上述例子中有ThreadDemo构造方法时,可以在new实例的时候直接命名,没有构造方法,可以通过setName()方法给线程命名。

String getName​():返回此线程的名称,需要注意的是,getName()方法只有thread类才可以直接用来获取线程名称,其余两种需要使用Thread.currentThread().getName()来获取当前线程名称。

public static void sleep(long time):让线程休眠指定的时间,单位为毫秒。

例子中我创建了2个线程分别命名为雅马哈和本田

运行结果:

 线程调度       

 多线程的并发运行时,计算机中的CPU,在任意时刻只能执行一条机器指令。每个线程只有获得CPU的使用权才能执行代码。各个线程轮流获得CPU的使用权,分别执行各自的任务。

线程有两种调度模型

1.分时调度模型:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片

2.抢占式调度模型:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的 CPU 时间片相对多一些

Java使用的是抢占式调度模型:

线程的优先级

public final void setPriority(int newPriority)    设置线程的优先级

public final int getPriority()        获取线程的优先级

这里上代码示例演示下,用Callable的方式实现:

首先定义一个mycallable类:

public static class MyCallable implements Callable<String> {@Overridepublic String call() throws Exception {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + "超车" + i);}//返回值就表示线程运行完毕之后的结果return Thread.currentThread().getName() +"完赛";}}

然后是实现方式:

 public static void main(String[] args) throws ExecutionException, InterruptedException {//优先级: 1 - 10 默认值:5MyCallable mc = new MyCallable();FutureTask<String> ducati = new FutureTask<>(mc);Thread t1 = new Thread(ducati);t1.setName("马力狗");t1.setPriority(10);System.out.println("马力狗马力优先级"+t1.getPriority());t1.start();System.out.println(ducati.get());MyCallable mc2 = new MyCallable();FutureTask<String> suzuki = new FutureTask<>(mc2);Thread t2 = new Thread(suzuki);t2.setName("GSX");t2.setPriority(1);System.out.println("GSX马力优先级"+t2.getPriority());t2.start();System.out.println(suzuki.get());
}

在优先级设置方法setPriority的源码中可以看到有两个参数控制最大最小优先级,最大是10,最小是1。在设置时不要超过这个范围,否则会引发报错

 由于电脑配置较高,而且执行的逻辑较简单,数据量小,所以运行结果体现不出cpu资源的竞争,看上去都是按着代码顺序执行的,就不展示结果了。

 以上内容如有不对欢迎指正,业余时间总结记录一下。


http://www.ppmy.cn/news/60668.html

相关文章

【A200】 TX1核心 JetPack4.6.2版本如何修改DTB文件测试全部SPI

大家好&#xff0c;我是虎哥&#xff0c;很长时间没有发布新内容&#xff0c;主要是这段时间集中精力&#xff0c;研究DTB设备树的修改&#xff0c;以适配不同载板&#xff0c;同时也是专门做了一个TX1&TX2核心&#xff0c;双网口&#xff0c;可以使用SPI 扩展CAN接口的载板…

揭秘是什么?让开屏广告效益几何增长

​在移动广告投放中&#xff0c;开屏广告是相当受欢迎的广告形式。开屏广告的受欢迎程度源于它具有很高的曝光率&#xff0c;用户在使用应用时通常就会看到开屏广告&#xff0c;因此开屏广告可以将广告内容传达给更多的用户&#xff0c;也拥有较高转化率。 接下来&#xff0c;…

解锁新技能《Spring Plugin插件系统》

平时工作过程中很少使用Spring Plugin插件&#xff0c;最近因为在学习springfox源码的过程中发现有大量用到&#xff0c;先来学习下插件的使用方法。 GitHub地址&#xff1a;https://github.com/spring-projects/spring-plugin 截止20230426日&#xff0c;GitHub的Star为403&…

JSP在线教学质量评价系统的设计与实现(源代码+论文)

在线教学质量评价系统可以方便和全面地收集教师教学工作的数据&#xff0c;提供师生网上评教的评分结果&#xff0c;快速集中收集各方面的评教信息&#xff0c;使教务管理部门能够及时了解教学动态和师资情况&#xff0c;为教务老师提供相关决策支持&#xff0c;为职称评聘提供…

2.压力测试+优化(Jmeter)

typora-copy-images-to: assert typora-root-url: assert 概述 1.性能指标 从外部看&#xff0c;性能测试主要关注如下三个指标【量越大越好&#xff0c;时间越少越好】吞吐量:每秒钟系统能够处理的请求数、任务数。响应时间:服务处理一个请求或一个任务的耗时。错误率:一批…

【Python】什么是爬虫,爬虫实例

有s表示加密的访问方式 一、初识爬虫 什么是爬虫 网络爬虫&#xff0c;是一种按照一定规则&#xff0c;自动抓取互联网信息的程序或者脚本。由于互联网数据的多样性和资源的有限性&#xff0c;根据用户需求定向抓取相关网页并分析已成为如今主流的爬取策略爬虫可以做什么 你可以…

深度学习笔记之卷积神经网络(一)卷积函数与图像卷积操作

深度学习笔记之卷积神经网络——卷积函数 引言什么是卷积图像卷积操作 引言 从本节开始&#xff0c;将介绍卷积神经网络。本节将介绍卷积函数。 什么是卷积 卷积&#xff0c;是一种通过两个函数 f ( ⋅ ) 和 f(\cdot)和 f(⋅)和 g ( ⋅ ) g(\cdot) g(⋅)生成第三个函数 h ( …

出海的中国企业,为什么有80%都选择了这家云服务商?

对于想要出海的中国企业来说&#xff0c;什么样的云服务才是他们的最佳选择&#xff1f; 中国企业出海驶入快车道 中国企业的出海大潮&#xff0c;多年来一直方兴未艾&#xff0c;并且得到了政府部门的大力支持。这股“走出去”的热潮&#xff0c;一方面对内有利于推动产业升级…