多线程基础

server/2024/12/23 7:09:09/

一锁两并三程

synchronized

并发和并行

并发(concurrent):在一台处理器上“同时”处理多个任务,即有多个任务在单个cpu上交替进行,但其实在同一时刻,只有一个任务在执行。

并行(parallel):在多台处理器上同时处理多个任务,即同一时刻,有多个指令在多个cpu上同时执行。例子:锅在加热的同时你在切菜。

2核4线程:可以最多同时运行4个线程,超过4个线程,则需要在这些线程间交替执行

进程、线程、管程

进程:在系统中运行的一个应用程序就是一个进程,每一个进程都有他自己的内存空间和系统资源。

例子“每个软件就是一个进程,idea、mindmanager2016、sublime、任务管理器都是进程

image-20240421223737828

线程:也被称为轻量级进程,在同一个进程内会有1个或多个线程,是大多数操作系统进行时序调度的基本单元。

例子:idea这个进程下有很多个线程

image-20240421224217721

管程:Monitor(监视器),也就是我们平时所说的锁。监视器是一种同步机制,他的义务是保证(同一时间)只有一个线程可以访问被保护的数据和代码。

例子:使用synchronized时,需要传入一个对象,此时传入的对象o就作为监视器

image-20240421224551988

总结:

执行线程要求先成功持有管程,然后才能执行方法,最后当方法完成(无论是正常完成还是非正常完成)时释放管程。在方法执行期间,执行线程持有了管程,其他任何线程都无法再获取到同一个管程。

多线程的实现方式

  1. 继承Thread类的方式进行实现

image-20240411234800057

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

image-20240412215136257

  1. 利用Callable接口和Future接口方式实现

image-20240412215918591

三种方式对比

image-20240412220057655

Thread类常用的方法

image-20240412221702840

  • setName和getName

设置线程名字的方法

  1. 如果没有给线程设置名字,线程的默认名字为Thread-X(X为序号,从0开始)

image-20240412222105010

注意:main方法所在的线程的名字为main

  1. 可以用setName方法设置线程名字,
  2. 可以在Thread的构造方法中设置线程的名字

image-20240412222327077

注意:使用构造方法设置线程名字时需要在实现类中构造方法中调用父类的构造方法

image-20240412223906940

  • currentThread

currentThread可以获取当前线程的对象,哪条线程执行到这个方法,此时获取的就是那条线程的对象

当JVM虚拟机启动之后,会自动的启动多条线程,其中有一条线程就叫做main线程,他的作用就是去调用main方法,并执行里面的代码。在以前,我们写的所有的代码,其实都是运行在main线程当中

  • sleep

sleep方法可以让线程休眠指定的时间,单位为毫秒(1秒=1000毫秒)。哪条线程执行到这个方法,那么那条线程就会在这里停留对应的时间。 当时间到了之后,线程会自动的醒来,继续执行下面的其他代码

  • setPriority和getPriority

cpu调度方式:

  1. 抢占式调度

多个线程抢夺cpu的执行权,cpu执行哪条线程是不确定的,执行多长时间也是不确定的,抢占式调度具有随机性。

jvm采用抢占式调度方式,所以每个线程何时执行,执行多长时间都是不确定的,线程的优先级越高,抢到cpu执行权的概率越大。

  1. 非抢占式调度

setPriority方法用来设置线程的优先级,优先级默认为5。优先级范围为1-10。

image-20240412230345732

注意:

main线程的默认优先级也是5

  • setDaemon

setDaemon方法用于设置守护线程,setDaemon方法必须用在start方法前。

image-20240412231701918

女神线程执行完毕后,备胎线程没有打印到“备胎@100”就提前结束了

image-20240412232018982

  • isDaemon

判断是否为守护线程

守护线程的应用场景:

  1. 垃圾回收线程

  2. 聊天的同时传输文件。聊天窗口为线程1,传输文件为线程2。关闭聊天窗口(关闭线程1)后,传输文件也会自动断开(关闭线程2)。此时可以把传输文件设置为守护线程,当关闭线程1后,线程2就会自动断开了。

image-20240412232209700

  • yield

yield方法会出让cpu的执行权

image-20240413190645661

  • join

image-20240413191046153

注意:

相当于把线程t加入到了main线程中,即把两个线程合并为单线程

线程的生命周期

image-20240413192145842

**问:**sleep方法会让线程睡眠,睡眠时间到了之后,立马就会执行下面的代码吗?

不会,阻塞状态结束后会进入就绪状态,而不是运行状态

线程的安全问题

需求:

某电影院目前正在上映国产大片,共有100张票,而它有3个窗口卖票,请设计一个程序模拟该电影院卖票

image-20240413194816053

出现的问题:

问题1:三个窗口同时卖同一张票

image-20240413194858792

问题2:窗口1和窗口3卖的票超出了100张

image-20240413195004133

原因:

一开始ticket=0,窗口1这个线程运行到if(ticket<100)时,符合条件,窗口1进入if的方法体内,运行到Thread.sleep(100)时,窗口1会进入阻塞状态,丢失cpu的执行权,此时cpu的执行权会被窗口2或窗口3抢走,假设窗口2抢到了执行权,此时ticket仍然是2,所以窗口2也会进入到if方法体内,运行到Thread.sleep(100)时,窗口2进入阻塞状态,假设此时窗口1仍处于阻塞状态,此时执行权一定会被窗口3抢走,同样的,此时ticket=2,窗口3运行Thread.sleep(100)时,窗口3进入阻塞状态。假设执行权又被窗口1抢走,窗口1执行完ticket++这条语句,此时ticket=1,碰巧窗口1在执行sout这条语句前,执行权被窗口2抢走,窗口2执行到ticket++后,此时ticket=2,碰巧窗口2执行sout这条语句前,执行权又被窗口3抢走,窗口3执行完ticket++后,此时ticket=3,窗口3继续向下执行,执行sout语句,此时输出“窗口3正在卖第3张票”,执行完sout这条语句后,执行权又被窗口1抢走,窗口1执行sout语句,此时输出“窗口1正在卖第3张票”,窗口2同理…

注意:

线程在执行任意语句后,执行权都概率被其他线程抢走,并不是线程进入阻塞状态后才有概率被其他线程抢走!Thread.sleep(100)只是为了方法这个现象!

解决办法:

办法1:同步代码块

把操作共享数据的代码锁起来

格式:

java">synchronized (锁对象) {操作共享数据的代码}

特点1:锁默认打开,有一个线程进去了,锁自动关闭

特点2:里面的代码全部执行完毕,线程出来,锁自动打开

同步代码块实现卖票:

image-20240413202800174

办法2:同步方法

就是把synchronized关键字加到方法上

格式:

java">修饰符 synchronized 返回值类型 方法名(方法参数) {...}

特点1:同步方法是锁住方法里面所有的代码

特点2:锁对象不能自己指定

非静态方法的锁对象是:this

静态方法的锁对象是:当前类的字节码文件对象

同步方法使用技巧:

先写同步代码块,然后将同步代码块改成同步方法

同步方法实现卖票:

  1. 先写成同步代码块的形式

image-20240413213244925

  1. 将同步代码块抽取成同步方法

image-20240413213919747

注意:MyRunnable实现了Runnable接口,开启多线程时使用MyRunnable mr = new MyRunnable(); Thread t1 = new Thread(mr);的方式,因为只创建了一个MyRunnable()对象,三个线程传入了相同的MyRunnable()对象,int ticket不需要加static关键字,因为三个线程访问的是同一个对象的ticket。

Lock锁

image-20240413235301682

实现方式

image-20240414000220356

死锁

男孩(线程1)和女孩(线程2)一起抢饭吃,但是只有两只筷子:筷子A(锁A)和筷子B(锁B)。规则:只有一个人同时拿到两只筷子才能吃饭,吃一口饭后要把筷子放到桌子上(释放锁),两个人重新抢筷子吃饭。

情况1:男孩(线程1)同时拿到筷子A(锁A)和筷子B(锁B),吃一口后放到重新将筷子A(锁A)和筷子B(锁B)桌子上。

情况2:女孩(线程2)同时拿到筷子A(锁A)和筷子B(锁B),吃一口后放到重新将筷子A(锁A)和筷子B(锁B)桌子上。

情况3:男孩(线程1)拿到筷子A(锁A),女孩(线程2)拿到筷子B(锁B),两个人都等待对方吃一口饭后放下筷子(释放锁)

情况4:男孩(线程1)拿到筷子B(锁B),女孩(线程2)拿到筷子A(锁A),两个人都等待对方吃一口饭后放下筷子(释放锁)

情况3和情况4就发生了死锁错误。

生产者和消费者(等待唤醒机制)

image-20240414003030443

常见方法:

image-20240414003114823

需求:

完成生产者和消费者(等待唤醒机制)的代码,实现线程轮流交替执行的效果

多线程的状态

image-20240414011623466

注意:

这些状态是运行在jvm态,并没有反应所有操作系统线程状态。

线程抢到cpu的执行权后,jvm就会把该线程交给操作系统,所以jvm上线程是没有运行状态的。

image-20240414012317254

线程池

线程池的主要原理:

image-20240414013250855

创建线程池的方法:

使用线程池工具类:Executors。通过调用Executors的静态方法来创建不同类型的线程池对象。

image-20240414013437791

使用线程池:

  1. 创建没有大小限制的线程池(线程池的大小为int所能表述的最大值)

  1. 创建固定大小的线程池

image-20240415223140904

image-20240415223057786

自定义线程池

自定义线程池的7个参数:

image-20240416004358917

注意1:

临时线程对象的最大数量=线程池中最大线程的数量-核心线程数量;

空闲时间指的是临时线程对象多长时间没有工作,则会将临时线程对象销毁。

注意2:

来任务了需要先创建核心线程对象,核心线程对象都是工作状态,再来任务的话会进入核心线程的队列中等待,核心线程队列满了才会创建临时线程对象;

线程执行顺序不是按照先来后到的规则,队伍里的线程会按照先来后到的规则执行等待核心线程执行,而队伍外的线程会使用临时线程执行;

核心线程对象都是工作状态,核心线程队伍满了,临时线程对象也都是工作状态,此时再来任务,会触发任务拒绝策略,默认拒绝策略是舍弃不要。

image-20240416005342773

任务拒绝策略:

image-20240416004305741

代码实现:

image-20240416004745908


http://www.ppmy.cn/server/10282.html

相关文章

单机三pxc节点集群,+docker-haproxy2.0负载均衡实现

一.下载 https://www.haproxy.org/download/2.0/src/haproxy-2.0.5.tar.gz 或者在这里下载&#xff08;下面需要的各个配置文件都有&#xff09;&#xff1a; https://download.csdn.net/download/cyw8998/89170129 二.编写文件&#xff0c;制作docker镜像 1.Dockerfile&a…

word 第十四课

管理工作表数据 数据排序&#xff1a;Excel可以对整个数据表或选中的单元格区域中的数据按文本、数字或日期和时间等进行升序或降序排列。数据筛选&#xff1a;使用筛选可使数据表中仅显示满足条件的行&#xff0c;不符合条件的行将被隐藏。Excel提供了两种数据筛选方式&#…

单链表的查询

单链表的查询操作是指通过给定的值或位置&#xff0c;找到链表中对应的节点。 首先&#xff0c;要实现单链表的查询操作&#xff0c;需要定义一个链表节点的数据结构&#xff0c;包含一个值域和一个指向下一个节点的指针。 假设链表的节点定义如下&#xff1a; class ListNo…

密码学系列4-选择密文安全,同态加密安全性

本章将介绍Cramer-Shoup加密方案,并证明其安全性。最后讨论了同态加密方案的安全性证明 一、Cramer-Shoup加密 密钥生成 1.定义群 G G G,群的阶为 q q q,选取群的生成元

MATLAB初学者入门(10)—— 粒子群算法

粒子群优化&#xff08;Particle Swarm Optimization, PSO&#xff09;是一种基于群体协作的优化技术&#xff0c;它由社会行为模型&#xff08;如鸟群觅食行为&#xff09;启发而来。PSO 通过模拟一群粒子&#xff08;候选解&#xff09;在解空间中的移动来寻找最优解。每个粒…

JavaEE初阶——多线程(六)——线程池

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 小比特 大梦想 此篇文章与大家分享多线程的第六篇文章,关于线程池 如果有不足的或者错误的请您指出! 目录 3.线程池3.1标准库的线程池3.2 标准库自己提供的几个工厂类3.3自己实现一个线程池完成大体框架接下来完…

Nginx下PHP连接到GBase 8s数据库 - PDO_GBASEDBT方式

PHP可以通过odbc&#xff0c;pdo_odbc和pdo_gbasedbt三种方式连接到GBase 8s数据库&#xff0c;这三种方式均需要通过CSDK客户端工具。 操作系统&#xff1a;CentOS 7.9 x86_64 必要组件&#xff1a; php及扩展&#xff0c;如php-fpm/php-odbc/php-pdo等nginx服务gcc/gcc-c …

虚拟化+Docker基本管理

一、虚拟化简介 1、云端 华为云、谷歌云、腾讯云、阿里云、亚马逊、百度云、移动云、天翼云、西部数码云等 1.国内云 华为云、阿里云、腾讯云、天翼云(私有云) 2.国外云 谷歌云、亚马逊 2、云计算的服务模式是分层的 IaaS&#xff1a;Infrastructure&#xff08;基础设…