多线程基础知识点

1. 进程

一个正在执行中的程序就是一个进程,系统会为这个进程发配独立的【内存资源】。进程是程序的一次执行过程,它有自己独立的生命周期,它会在启动程序时产生,运行程序时存在,关闭程序时消亡。

例如:正在运行的 QQ、IDE、浏览器就是进程。

2. 线程

线程是由进程创建的,是进程的一个实体,是具体干活的人,一个进程可能有多个线程。线程不独立分配内存,而是共享进程的内存资源,线程可以共享 CPU 的计算资源。

一个进程的线程就不能修改另一个线程的数据,隔离性更好,安全性更好。

3. 并发和并行

大部分操作系统的任务调度是采用时间片轮转的抢占式调度方式,也就是说一个任务执行一小段时间后强制暂停去执行下一个任务,每个任务轮流执行。CPU 在不同的进程之间轮换,进程又在不同的线程之间轮换,因此线程是 CPU 执行和调度的最小单元。

任务执行的一小段时间叫做时间片,任务正在执行时的状态叫运行状态,任务执行一段时间后强制暂停去执行下一个任务,被暂停的任务就处于就绪状态,等待下一个属于它的时间片的到来。这样每个任务都能得到执行,由于 CPU 的执行效率非常高,时间片非常短,在各个任务之间快速地切换,给人的感觉就是多个任务在“同时进行”,这也就是我们所说的并发。

并发是两个队列交替使用一台咖啡机。

并行是两个队列同时使用两台咖啡机。

4. Java 中常见线程方式

4.1 继承 Thread 类

步骤:

  • 定义类继承 Thread;
  • 重写 Thread 类中的 run 方法;
  • 调用线程的 start 方法:
public class Test01 {public static void main(String[] args) {System.out.println(1);new MyThread01().start();System.out.println(3);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(4);} 
}class MyThread01 extends Thread{@Overridepublic void run() {System.out.println(2);}
}

4.2 实现 Runnable 接口

步骤:

  • 创建类实现 Runnable 接口
  • 使用 Thread 为这个任务分配线程
  • 调用线程的 start 方法
public class Test02 {public static void main(String[] args) {System.out.println(1);//注意,这里 new 的是 Threadnew Thread(new MyRun()).start();System.out.println(3);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(4);}}class MyRun implements Runnable{public void run() {System.out.println(2);}
}

4.3 实现 Callable 接口

步骤:

  • 创建类实现 Callable 接口
  • 通过 Callable 接口实现类创建 FutureTask
  • 使用 Thread 为这个 FutureTask 分配线程
  • 调用线程的 start 方法
public class Test03 {public static void main(String[] args) throws ExecutionException, InterruptedException {System.out.println(2);FutureTask<Integer> futureTask = new  FutureTask<>(new MyCallable());System.out.println(3);new Thread(futureTask).start();System.out.println(4);int result = futureTask.get();System.out.println(5);System.out.println(result);System.out.println(6);}}class MyCallable implements Callable<Integer> {public Integer call() throws Exception {Thread.sleep(2000);return 1;}
}

futureTask.get(); 是一个阻塞的方法,意思就是,这个方法会一直等,主线程会一直等待,这个线程执行完成之后并有了返回值,才会继续执行。

5. 守护线程

Java 提供两种类型的线程: 用户线程和守护线程。

守护线程旨在为用户线程提供服务,并且仅在用户线程运行时才需要。

守护线程对于后台支持任务非常有用,例如垃圾收集,释放未使用对象的内存以及从缓存中删除不需要的数据。大多数 JVM 线程都是守护线程。

要将线程设置为守护线程,我们需要做的就是调用 Thread 的 setDaemon() 方法。

NewThread t = new NewThread();
t.setDaemon(true);
t.start();

6. 线程的生命周期

生命周期可以通俗地理解为“从出生到死亡”的整个过程。线程的生命周期包括从创建到销毁的整个过程。

线程的状态:

  • NEW - 初始状态,一个新创建的线程,还没开始执行。
  • RUNNABLE - 可执行的状态,要么是在执行,要么是一切就绪等待执行,例如等待分配 CPU 时间。
  • WAITING - 等待状态,等待其他的线程去执行特定的动作,没有时间限制。
  • TIMED_WAITING - 限时等待状态,等待其他的线程去执行特定的动作,这个是在一个指定的时间范围内。
  • BLOCKED - 阻塞状态,等待锁,以便进入同步块儿。
  • TERMINATED - 终止状态,线程执行结束。

图片描述

7. 线程常用方法

currentThread() :该方法是 Thread 类中的类方法,可以用类名调用,方法返回当前正在使用 CPU 资源的线程。

sleep() :使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁。

join() :让当前线程邀请调用方法的那个线程优先执行,在被邀请的线程执行结束之前当前线程一直处于阻塞状态,不再继续执行。

yield() :让当前线程直接放弃时间片返回就绪状态。

wait() :当前线程放弃监视器并进入睡眠状态,直到其他进入同一个监视器的线程调用 notify 为止。

notify() :唤醒同一监听器中调用 wait 的某一个线程。

notifyAll() :唤醒同一监听器中所有等待的线程。

8. 线程安全

如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

9. 线程同步

线程同步:关键字 synchronized。

使用同步监视器来判断当前代码是否有线程在执行。线程开始执行同步代码块之前,必须先获得对同步监视器的锁。

任何时刻只能有一个线程可以获得对同步监视器的锁定,当同步代码块执行结束后,该线程自然会释放对同步监视器对象的锁。

Java 程序运行可以使用任何对象来作为同步监视器对象。

synchronized 有三种方式来加锁,分别是:

  1. 修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁
  2. 静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁
  3. 修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。

10. synchronized 原理

Synchronized 底层是通过两个方法来完成同步:

  • monitorenter
  • monitorexit

10.1 monitorenter

每个对象有一个监视器锁(monitor)。当 monitor 被占用时就会处于锁定状态,线程执行 monitorenter 指令时尝试获取 monitor 的所有权,过程如下:

  1. 如果 monitor 的进入数为 0,则该线程进入 monitor,然后将进入数设置为 1,该线程即为 monitor 的所有者。

  2. 如果线程已经占有该 monitor,只是重新进入,则进入 monitor 的进入数加 1.

  3. 如果其他线程已经占用了 monitor,则该线程进入阻塞状态,直到 monitor 的进入数为 0,再重新尝试获取 monitor 的所有权。

10.2 monitorexit

执行 monitorexit 的线程必须是 objectref 所对应的 monitor 的所有者。

指令执行时,monitor 的进入数减 1,如果减 1 后进入数为 0,那线程退出 monitor,不再是这个 monitor 的所有者。其他被这个 monitor 阻塞的线程可以尝试去获取这个 monitor 的所有权。

11. 死锁

死锁问题:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放,而该资源又被其他线程锁定,从而导致每一个线程都得等其它线程释放其锁定的资源,造成了所有线程都无法正常结束。结构如下图所示:

死锁示例代码:

public class MyThread01 implements Runnable{static Object garlic = new Object();static Object vinegar = new Object();int flag = 0;@Overridepublic void run() {if (flag == 0) {synchronized (vinegar) {try {Thread.sleep(500);} catch (InterruptedException e) {return;}System.out.println("我张三正在吃醋,李四你给我点蒜瓣");synchronized (garlic) {System.out.println("我张三终于吃上蒜了,hiahia~");}}}if (flag == 1) {synchronized (garlic) {try {Thread.sleep(500);} catch (InterruptedException e) {}System.out.println("俺李四正在吃蒜,张三你给我点醋");synchronized (vinegar) {System.out.println("我李四终于吃上醋了,hiahia~");}}}}public static void main(String[] args) {MyThread01 ZhangSan = new MyThread01();MyThread01 LiSi = new MyThread01();ZhangSan.flag = 0;LiSi.flag = 1;Thread t1 = new Thread(ZhangSan);Thread t2 = new Thread(LiSi);t1.start();t2.start();}
}

程序运行结果:

图片描述

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

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

相关文章

胡圆圆的暑期实习经验分享

背景 实验室一般是在研究生二年级的时候会放实习&#xff0c;在以后的日子就是自己完成毕业工作要求&#xff0c;基本上不再涉及实验室的活了&#xff0c;目前是一月份也是开始准备暑期实习的好时间。实验室每年这个时候都会有学长学姐组织暑期实习经验分享&#xff0c;本着不…

uView IndexList 索引列表

通过折叠面板收纳内容区域 #平台差异说明 App&#xff08;vue&#xff09;App&#xff08;nvue&#xff09;H5小程序√√√√ #基本使用 外层包裹一个index-list组件&#xff0c;锚点通过index-anchor组件传入&#xff0c;自定义列表内容通过index-item嵌套使用 nvue需要将…

【Redis】非关系型数据库之Redis的增删改查

目录 一、Redis的数据类型分类 二、Redis的字符串类型string 三、Redis的列表list 四、Redis的哈希hash 五、Redis的无序集合set 六、Redis的有序集合zset 七、Redis的通用命令 一、Redis的数据类型分类 通常Redis的数据类型有五大基础类型 String&#xff08;字符串&am…

Beauty algorithm(二)唇妆

实现唇妆过程中首先确定唇部位置,其次对该区域进行渲染。 一、skills 前瞻 1、cv::convexHull 在点集中寻找凸包点 void convexHull( InputArray points, OutputArray hull, bool clockwise = false, bool returnPoints = true ); 参数poi…

安全加固之weblogic屏蔽T3协议

一、前言 开放weblogic控制台的7001端口&#xff0c;默认会开启T3协议服务&#xff0c;T3协议则会触发的Weblogic Server WLS Core Components中存在反序列化漏洞&#xff0c;攻击者可以发送构造的恶意T3协议数据&#xff0c;获取目标服务器权限。 本文介绍通过控制T3协议的访问…

[JavaWeb玩耍日记] 数据库

mysql版本&#xff1a;5.7.24 使用Navicat for MySQL辅助学习(2015年版)&#xff0c;这个在粘贴本博客的块引用内容时会有额外的不可见内容导致sql运行出问题&#xff0c;不过有影响的地方笔者已排除 目录 一.数据库创建 二.使用数据库与创建表 三.表内列的数据类型 四.修…

【开源】基于JAVA语言的服装店库存管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 角色管理模块2.3 服装档案模块2.4 服装入库模块2.5 服装出库模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 角色表3.2.2 服装档案表3.2.3 服装入库表3.2.4 服装出库表 四、系统展示五、核心代码5.…

对Tor的去匿名化攻击的调查

文章信息 论文题目&#xff1a;De-Anonymisation Attacks on Tor: A Survey 期刊&#xff08;会议&#xff09;&#xff1a; IEEE Communications Surveys & Tutorials 时间&#xff1a;2021 级别&#xff1a;中科院1区&#xff08;IF&#xff1a;35.6&#xff09; 文章链…

软件测试|Docker exec命令详细使用指南

简介 Docker exec命令是Docker提供的一个强大工具&#xff0c;用于在正在运行的容器中执行命令。本文将详细介绍Docker exec命令的用法和示例&#xff0c;帮助大家更好地理解和使用这个命令。 Docker是一种流行的容器化平台&#xff0c;允许我们在容器中运行应用程序。有时候…

【DevOps-06】Jenkins实现CI/CD操作

一、简要说明 基于Jenkins拉取GitLab的SpringBoot代码进行构建发布到测试环境实现持续集成 基于Jenkins拉取GitLab指定发行版本的SpringBoot代码进行构建发布到生产环境实现CD实现持续部署 二、准备Springboot工程 1、IDEA新建工程 2、填写项目工程信息 3、选择Springboot版本…

条款18:让接口容易被正确使用,不易被误用

假设正在为一个表示时间日期的类设计构造函数: class Date { public:Date(int month, int day, int year);... }; Date d(30, 3, 1995); // 糟糕! 应该是 “3, 30” , 而不是 "30, 3" Date d(2, 30, 1995); // 糟糕! 应该是 "3, 30" , 而不是 "2, 30…

游戏美术的技与艺

大家好&#xff0c;我是阿赵。   可能很多朋友都知道&#xff0c;我刚进入游戏行业的时候&#xff0c;做的是美术工作&#xff0c;包括了建模、贴图、动画等&#xff0c;都做过。我对各种美术资源制作也都很熟悉&#xff0c;懂得很多制作的技术。但最后&#xff0c;我却没有继…

李沐-《动手学深度学习》-- 01-预备知识

一、线性代数知识 1. 矩阵计算 a. 矩阵求导 ​ 当y和x分别为标量和向量时候&#xff0c;进行求导得到的矩阵形状&#xff0c;矩阵求导就是矩阵A中的每一个元素对矩阵B中的每一个元素求导 ​ 梯度指向的是值变化最大的方向 ​ 分子布局和分母布局&#xff1a; b. 常识 ax…

美格智能5G RedCap模组SRM813Q通过广东联通5G创新实验室测试认证

近日&#xff0c;美格智能5G RedCap轻量化模组SRM813Q正式通过广东联通5G创新实验室端到端的测试验收&#xff0c;获颁测评证书。美格智能已连续通过业内两家权威实验室的测试认证&#xff0c;充分验证SRM813Q系列模组已经具备了成熟的商用能力&#xff0c;将为智慧工业、安防监…

【漏洞复现】润申信息管理系统SQL注入漏洞

漏洞描述 申信息科技企业标准化管理系统 DefaultHandler.ashx SQL注入漏洞 免责声明 技术文章仅供参考&#xff0c;任何个人和组织使用网络应当遵守宪法法律&#xff0c;遵守公共秩序&#xff0c;尊重社会公德&#xff0c;不得利用网络从事危害国家安全、荣誉和利益&#x…

.NET某软件非托管泄露分析

一:背景 遇到过很多程序的故障和杀毒软件扯上了关系,有杀毒软件导致的程序卡死,有杀毒软件导致的程序崩溃,这一篇又出现了一个杀毒软件导致的程序非托管内存泄露,真的是分析多了什么鬼都能撞上。 开启了ust并在内存超出预期时抓了一个dump下来,接下来就是分析了。 二:W…

gRCP - 面向未来的第二代 RPC 技术,解析 HTTP2.0 和 Protobuf

目录 一、gRCP - 面向未来的第二代 RPC 技术 1.1、gRPC 简介 1.1.1、gRPC 是个啥&#xff1f; 1.1.2、gRPC 核心设计思路 1.1.3、gRPC 和 ThriftRPC 区别 1.1.4、为什么使用 gRPC&#xff1f;&#xff08;好处&#xff09; 1.2、HTTP2.0 协议 1.2.1、回顾 HTTP1.0 和 H…

数据结构-怀化学院期末题

希尔排序 题目&#xff1a; 利用希尔排序算法实现线性表的排序。希尔排序是根据给定的增量序列将线性表分隔成某个“增量”的记录组成一个子序例&#xff0c;在子序列中采用直接插入排序完成。 输入 第一行为元素个数n(1<n<1000)&#xff0c;第二行为n个元素值(整数)&am…

【C++】带你学会使用C++线程库thread、原子库atomic、互斥量库mutex、条件变量库condition_variable

C线程相关知识讲解 前言正式开始C官方为啥要提供线程库thread构造函数代码演示this_threadget_id()yield()sleep_until和sleep_for mutex构造函数lock和unlock上锁全局锁局部锁lambda表达式 try_lock 其他锁时间锁递归版本专用锁recursive_mutex 锁的异常处理lock_guardunique_…

Linux_CentOS_7.9_Oracle11gr2配置数据库及监听服务自启动多方案实操之简易记录

前言: 作为运维保障,都无法准确预估硬件宕机的突发阶段,其生产数据实时在产出,那作为dba数据库服务以及相关Listener的其重要性、必要性就突显而出。这里拿虚拟机试验做个配置记录,便于大家学习参考。 实现方法一: 环境变量值::$ORACLE_HOME= /data/oracle/product/1…