JavaEE

您所在的位置:网站首页 奇葩父亲为省彩礼是哪一集 JavaEE

JavaEE

2023-03-14 03:01| 来源: 网络整理| 查看: 265

文章目录 一、认识线程1. 线程的概念2. 出现多线程的原因3. 进程与线程4. 对多线程的详细解释 二、初次实现多线程代码1. 初步了解2. 使用 Java 中的工具查看当前的所有线程3. Java 中创建线程的多种方式

一、认识线程 1. 线程的概念

所谓线程,就是指在一个 ‘执行流’ 中多个线程之间都可以按照自己的顺序执行代码,多个线程之间可以 ‘同时’ 执行多个代码。

2. 出现多线程的原因

首先,并发编程成为了刚需。

随着科技的发展,目前 CPU 的核心已近难以在进行缩小,想要得到更高的算力 “多核” CPU 成为了一种可行的解决方案,因此,并发编程来利用 CPU 资源的操作应运而生。有些任务操作中需要等待 “IO”,为了让等待的时间不被浪费,此时多线程的优势就体现了出来。

其次,虽然 多进程 也可以实现 并发编程,但是,线程 比 进程 更加轻量

注: 所谓轻量,就是在解决并发编程的前提下,让创建,销毁,调度的速度更快一些。

线程为啥更轻,就是将 申请资源&释放资源 的操作省去了! 下面我给大家简单举一个生活中的例子来解释一下。

我们先设想一个物流的中转站,如图:

在这里插入图片描述 这里就类似于一个进程在执行相关操作。

此时,因为某些原因,运输到我们中转站管辖范围的货物突然增多,为了更好的对快递进行配送,我们就必须要扩建。

无需多虑,这里会有两种操作可供我们选择。

操作一:重新在城市中找一块地方,建立一个新仓库用来缓解物流压力。

在这里插入图片描述 如图,就是将原来的模式完全复制一份。相当于 多进程 方案

操作二:将原来的厂房进行整理,在其中新建一个仓库即可。

在这里插入图片描述 这里不难发现,第二种方案,显然比第一种方案成本要小很多,场地和快递分配体系都是可以套用之前的。

这就是 多线程 版本的方案,此时,只要在第一次申请资源时,合理申请,之后增加的操作只需要复用第一次的申请的资源即可,不需要在进行资源的申请等操作…

3. 进程与线程

线程和进程的关系:进程 包含 线程。 一个进程中至少包含一个线程,一个进程可以包含多个线程。

进程和线程的关系图表,如下所示: 在这里插入图片描述 我们可以清晰地观察到,同一个进程中的多线程,共用着同一份资源(主要指内存,文字描述符表)

注:

进程是系统 资源分配 的最小单位,线程是系统 调度 的最小单位。一个 线程 是通过一个 PCB 来描述,即,PCB中的状态,上下文,优先级,记账信息等,每一个 线程 都是独立拥有的。在 同一个进程 的 多个线程 中 PCB 之间,他们的 pid 是相同的,即,内存指针和文件描述符表是相同的。 4. 对多线程的详细解释

对于多线程的解释,在这里我们依然可以用一个比较有趣的例子来解释。

首先,我们可以设想一个华强劈瓜的情景。

在这里插入图片描述 现在我们知道,要想让华强更好的,更快的进行劈瓜,就需要让华强分身到一个房间中一块劈(即,多线程)。

此时,我们让华强老铁造出更多分身出现在房间中,呢么劈瓜效率就一定会很快吗? 如图: 在这里插入图片描述 其实不难发现,华强老铁的增多并不能无限的加快劈瓜的速度。

桌子周围的空间是有限的 (即,CPU 上的核心数量是有限的)。

华强老铁太多,最终会出现相互推嚷的情况,让正在用力劈瓜的华强劈歪来。也就是说线程数量太多,核心数量有限,使得大量的时间花费在了线程调度上了

在多线程的条件下,如果某两个华强老铁,一眼看上了同一个瓜,争抢着去劈,此时就可能会打架。

在这里插入图片描述 这种情况在 多进程 中就不会出现,因为多进程是将瓜分配到单独的房间,由一个华强老铁来劈的。 因此,这里就引出了一个线程安全问题。

多线程下还会有一个问题 在这里插入图片描述 两个华强同时看上一个瓜,1号华强率先下手劈了瓜,2号华强很生气,直接就把瓜摊子掀了,大家都劈不了了。也就是说,如果一个线程出现了问题,如果没有处理好,呢么就有可能导致整个进程崩溃,其他线程也就被迫停止了! 二、初次实现多线程代码 1. 初步了解

首先,我们要知道在 Java 中要实现多线程的一个关键的类 Thread 类。 这里,我先展示一段代码,之后再进行详细的解释。

class MyThread extends Thread{ //重写线程类中的 run 方法 public void run(){ while(true){ System.out.println("hello thread"); //为了让执行变慢加一个 sleep try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class ThreadDemo { public static void main(String[] args) { Thread t = new MyThread(); //一个线程的创建 t.start(); //main 方法中主线程的代码实现 while(true){ System.out.println("hello main"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }

在这里插入图片描述 此处的 start 就只是创建了一个新的线程,注意,start 没有调用 run 方法。

这里创建新线程就是调用操作系统的 API ,通过操作系统内核创建出此线程的 PCB,并且将要执行的指令传递给这个 PCB,当 PCB 被调度到 CPU 上时,就会执行到其中的 run 方法中。 简单来讲,就是 main 方法中的 start 创建新线程,新线程内调用 run 方法。

start 和 run 方法之间的区别 start是真正的从系统资源里创建的独立的执行流。 run 方法只是描述了线程中需要干的工作。(在,main 方法中调用 run 此时,没有创建任何线程,只有 main 线程在进行工作)

代码执行结果:

在这里插入图片描述 注:这里只是部分结果截取。

在上述的结果中,我们不难看出,两个线程之间执行的先后顺序似乎并不固定,这里就需要提到操作系统调用线程时的方式——抢占式调用。

因此,哪个进程线上,那个进程后上,完全是取决于操作系统调度器的具体实现策略。

2. 使用 Java 中的工具查看当前的所有线程

(1)在安装 jdk 的 bin 目录下,找到上图中的 jconsole 程序。

如图所示: 在这里插入图片描述 (2)运行多个线程的代码的同时,打开程序。

在这里插入图片描述

(3)选择自己的线程后连接,之后点击线程,左下角就会出现如下图的情况。

在这里插入图片描述

3. Java 中创建线程的多种方式 继承 Tread 重写 run 方法。 class MyThread extends Thread{ //重写线程类中的 run 方法 public void run(){ while(true){ System.out.println("hello thread"); //为了让执行变慢加一个 sleep } } } public class ThreadDemo1 { public static void main(String[] args) { Thread t = new MyThread(); //start 表明创建一个线程,新线程 t.start(); while(true){ System.out.println("hello main"); } } } 实现 Runnable 接口 // Runnable 作用,是描述一个“要执行的任务”,run方法就是任务执行的细节 class MyRunnable implements Runnable{ @Override public void run() { System.out.println("hello thread"); } } public class ThreadDemo2 { public static void main(String[] args) { //这只是描述了个任务 Runnable runnable = new MyRunnable(); //把任务交给线程执行 Thread t = new Thread(runnable); t.start(); } } 使用 匿名内部类 来继承 Thread 方法。 //使用匿名内部类来实现线程的创建 public class ThreadDemo3 { public static void main(String[] args) { //这里创建了 Thread 的子类,但是子类没有名称 //但是创建了子类的实例,让 t 指向了该实例,并重写了其中的 run 方法。 Thread t = new Thread(){ public void run(){ System.out.println("hello"); } }; t.start(); } } 使用 匿名内部类 实现 Runnable

这里的匿名内部类不需要再进行解释

public class ThreadDemo4 { public static void main(String[] args) { //这里与第二种方法极为相似,是直接将 runnable 实例化后传递给匿名内部类 Thread t = new Thread(new Runnable(){ @Override public void run() { System.out.println("hello"); } }); t.start(); } } 使用 Lambad 表达式 // lambda 表达式 public class ThreadDemo5 { public static void main(String[] args) { Thread t = new Thread(() -> { System.out.println("hello"); }); t.start(); } }

到此, 文章结束, 如有不足, 欢迎提出. 如有错误, 欢迎指正!



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3