一篇搞懂Java多线程运行机制

您所在的位置:网站首页 守护进程的原理和方法 一篇搞懂Java多线程运行机制

一篇搞懂Java多线程运行机制

2024-07-09 22:01| 来源: 网络整理| 查看: 265

在这里插入图片描述

文章目录 前言线程并发和并行 Runnable接口Thread类线程的创建原理和注意事项为什么不直接调用run方法? 线程终止和中断用户线程和守护线程代码演示

前言

Java是一种支持多线程编程的语言。多线程可以让程序同时执行多个任务,从而提高程序的效率和响应速度。在本篇博客中,我将介绍Java多线程的基础知识,包括线程的创建、启动、中断以及线程同步等方面。

什么是程序? 程序是为完成特定任务,用某种语言编程写的一组指令的集合。一组计算机能识别和执行的指令,运行于电子计算机上,满足人们某种需求的信息化工具(简单来说就是我们写的代码)

什么是进程? 进程是指运行中的程序,比如我们使用的QQ,启动qq.exe可执行程序就启动了一个线程,操作系统就会为进程分配内存空间。当我们使用迅雷,又启动了一个进程,操作系统将为迅雷分配新的内存空间。

进程是程序的一次执行过程,或正在运行的一个程序。是动态过程:有它自身的产生、存在和消亡的过程。具体关系如图所示: 在这里插入图片描述

打开电脑的任务管理器,即可查看电脑运行的进程 在这里插入图片描述 进程共有三种状态:就绪、阻塞和运行

就绪态:就绪状态是指程序已达到可以运行的状态,只等CPU分配资源就可以运行的状态。阻塞态:当程序运行条件没有满足时,需要等待条件满足时候才能执行时所处的状态,如等待i/o操作时候,此刻的状态就叫阻塞态。运行态:进程占用CPU,并在CPU上运行。即程序正在运行时所处的状态。 线程

线程是由进程创建的,是一个进程的实体,一个进程可以有多个线程。比如:百度网盘的下载任务,一个下载任务对应一个线程,当同时下载多个任务时,相当于开启了多个线程,线程分为单线程和多线程。

单线程:同一时刻,只允许执行一个线程多线程:同一时刻,可以执行多个线程

在Java中线程使用有两种方式

继承Thread类,重写run方法实现Runnable接口,重写run方法 并发和并行

早期计算机的 CPU 都是单核的,一个 CPU 在同一时间只能执行一个进程/线程,当系统中有多个进程/线程等待执行时,CPU 只能执行完一个再执行下一个。并发和并行是用来操作线程和进程的方式。

并发 同一时刻,多个任务交替执行,造成一种同时的错觉,并不是正在同时运行。(单核CPU实现的多任务就是并发) 在这里插入图片描述 并行 同一时刻,多个任务同时执行,多核CPU可以实现并行。 在这里插入图片描述

注意:也可能会有并发和并行同时存在

Runnable接口

一个实现Runnable接口的类就是一个线程,通过Thread类启动。需要把实现类对象传入Thread类的构造方法中 然后通过Thread的start方法启动该Runnable实现类的线程。(因为Java是单继承机制,所以当有某个类已经继承了某个父类时,则需要用到Runnable接口)

该接口中只有一个**run()**方法,所以需要传入Thread类的构造器中进行启动

Thread类

Java语言是支持多线程的,一个正在运行的Java程序可以称之为一个进程(process),在每个进程里面包含多个线程.一个Thread实例对象,就是一个线程。Thread类继承于Runnable接口 在这里插入图片描述 常用方法

getName():获取当前线程的名称,默认线程名称是Thread-索引setName(String name):将此线程的名称更改为指定的名称,通过构造器也可以设置线程名称sleep(long time):让当前线程休眠指定的时间后再继续执行,单位是毫秒。run():线程任务方法(线程需要执行的业务内容)start():开启当前线程currentThread():获取当前执行线程的引用对象setPriority(int newPriority) :更改线程的优先级getPriority():获取线程的优先级interrupt():中断线程yield():给调度程序的一个提示,当前线程愿意得到它当前的处理器的使用(线程的礼让)join():线程的插队

用来控制线程优先级的范围常用的有三种:

MAX_PRIORITY线程可以拥有的最大优先级(10)MIN_PRIORITY线程可以拥有的最小优先级(1)NORM_PRIORITY被分配给线程的默认优先级(5)

注意:Thread类本身没用run方法的,而是继承Runnable接口重写得来的

使用start方法,会自动开启子线程,调用run方法。这里使用了设计模式(代理模式)

线程的创建

在Java中,可以通过继承Thread类或实现Runnable接口来创建一个线程。继承Thread类需要重写run()方法,而实现Runnable接口需要实现run()方法。下面是两种创建线程的示例代码:

继承Thread类的方式: public class MyThread extends Thread { @Override public void run() { // 线程执行的代码 } } MyThread myThread = new MyThread(); myThread.start(); // 启动线程 实现Runnable接口的方式: public class MyRunnable implements Runnable { @Override public void run() { // 线程执行的代码 } } MyRunnable myRunnable = new MyRunnable(); Thread thread = new Thread(myRunnable); thread.start(); // 启动线程 原理和注意事项

当执行执行代码程序时(run),会开启一个进程。之后会进入到主方法main中,会开启一个主线程(main线程) 在这里插入图片描述

可在控制台使用 jconsole指令监控线程执行情况,如果出现 不是内部或外部命令,也不是可运行的程序或批处理文件 。则需要检查jdk环境配置(建议手动配置)

注意:执行时需要开启需要监控的线程,才能进行查看

当主线程执行完毕后,子线程未执行完,则继续执行,执行完毕所有线程后,程序进程退出当程序进程结束,所有线程直接结束 为什么不直接调用run方法?

xx.run(); xx.start();

为什么不在主方法中直接调用run,而是通过start方法开启线程

如果使用xx.run()方法,则是主线程直接调用run方法,而此时线程的名称是main(此时的run方法就是一个普通的方法,并没有真正的启动子线程,会阻塞这里,等待run方法执行完毕,才会继续执行main主方法中代码);而使用xx.start()方法,则是通过子线程调用run方法(底层是JVM调用的,相当于开启了一个子线程)

start方法调用后,该线程并不一定会立刻马上执行,只是将线程变成了可运行状态。具体什么时候执行,取决于CPU,由CPU统一调度。

在这里插入图片描述

线程终止和中断

线程终止的两种情况:

当线程完成任务后,会自动退出通过使用变量来控制run方法退出的方式停止线程,即通知方式

中断 interrupt方法,用来中断线程,但并没有真正的结束线程,所以一般用于中断正在休眠的线程,此时调用该线程的interrupt方法,那么该线程将抛出一个InterruptedException中断异常,从而提早地终结被阻塞状态。如果线程没有被阻塞,这时调用 interrupt()将不起作用,直到执行到wait(),sleep(),join()时,才马上会抛出 InterruptedException。

如果需要中断一个线程,可以调用线程的interrupt()方法。但是,中断线程只是给线程一个中断的标志位,并不能直接终止线程的执行。线程需要自己在执行的过程中检查这个标志位,并在合适的时候终止自己的执行。下面是一个简单的中断线程的示例代码:

Thread thread = new Thread(() -> { while (!Thread.currentThread().isInterrupted()) { // 线程执行的代码 } }); thread.start(); // 启动线程 // 中断线程 thread.interrupt(); 用户线程和守护线程

Java的线程可以分为两类:User Thread(用户线程)、Daemon Thread(守护线程)

用户线程:也叫工作线程,当线程的任务执行完毕或以通知的方式来结束,平时用到的普通线程均是用户线程,当在Java程序中创建一个线程,它就被称为用户线程守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束。所以当系统只剩下守护进程的时候,Java虚拟机会自动退出。

如何将一个线程设置为守护线程? 需要使用Thread类中的setDaemon方法

setDaemon(boolean on):为true是守护线程,反则为false,线程默认是用户线程(此方法必须在开始线程之前调用)

当主线程结束,子线程自动结束,将子线程设置为守护线程,演示如下

public class ThreadTest3 { public static void main(String[] args) { DaemonThread daemonThread = new DaemonThread(); daemonThread.setDaemon(true); daemonThread.start(); for (int i = 1; i


【本文地址】


今日新闻


推荐新闻


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