并发编程(一)-----为什么要使用并发编程

一. 为什么要使用并发编程?

并发编程的主要目的是为了使程序运行的更快;

但是下一个问题出来了,并发编程一定会使我们的程序运行的更快吗?为什么并发编程会使我们的程序变得更快呢?

二. 理解并发编程

2.1并发编程一定会使我们的程序运行的更快吗?

答案是并不是,并发编程只有在一定的请求量或者计算量的时候才会显示出优势;

2.2 为什么有的时候多线程反而会变慢呢?

我们知道os(操作系统)执行并发操作是采用的时间片轮转算法,简单的说就是线程1先执行10ms 然后线程B在执行10ms 然后线程A又执行了10ms 线程A执行完毕 线程B又开始执行到结束

我们可以发现这种执行的机制,会导致cpu一会执行A线程 一会执行B线程,这就导出了一个第一个导致多线程慢的因素:线程的上下文切花需要时间
补充:Java创建多线程需要OS的干预,OS需要从用户态切换到核心态 这个过程很耗费时间

那么简单的理解就是:如果多线程执行的速度快于单线程执行的速度,那么我们可以理解为多线程一定会在执行前做一些准备,而单线程不需要,所以当任务数或者工作量并不大的时候单线程就会很有优势;但是当任务数上来后多线程的优势就体现出来了;
这里我们有个可以继续深入研究的点:即具体什么时候,什么情况下单线程执行优于多线程

2.3 那么如何提高并发编程的性能呢?

我们知道并发性能的瓶颈就是频繁的上下文切换,那么我们就可以通过减少上下文的切换来提高性能。

减少上下文切换的方法又一下几种

  1. 采用无锁并发编程:多线程竞争锁的时候就会引起上下文的切换,所以处理数据的时候应该避免加锁,可以把数据分段,每个线程来处理一段的数据,

  2. CAS算法: Java的Atomic包使用CAS算法来更新数据,不需要加锁

  3. 尽量合理的配置线程即使用最少的线程:例如我们处理一个任务10个线程100ms搞定,那么你开100000个线程来处理,光上下文切换的时间都要超过100ms

  4. 使用协程:在单线程里实现任务的调度,并在单线程里维持多个任务的切换

2.2 为什么并发编程会使我们的程序变得更快呢?

首先对于单线程来说,程序是一行一行的执行的,所以假设在120行-180行之间的程序含有数据库操作需要等待很长时间,那么180行以后的代码都必须等到180行的代码执行完才能继续执行,而并发编程其实就是异步化,也就是主线程在执行到120行的时候,120-180行的代码交给另一个线程去执行,主线程可以继续向下执行,所以两件事是并行的,所以程序的响应时间就会变快

三.线程相关的概念:

**进程:**什么是进程?在windows的资源管理器中,每个正在运行的exe程序都是一个进程。进程占用着cpu,内存,磁盘,网络等资源。站在操作系统的层面上来说进程是分配资源的基本单位,也是最小单位,换种说说法也就是受操作系统管理的基本运行单元。(我们的程序代码也是进程的一部分)。

**线程:**可以理解为进程中独立的子任务,一个进程中至少存在一条线程。线程是进程中负责程序执行的执行单元,也就是实际功能的执行者。举个例子:看直播的时候,可以看直播的时候发送弹幕,还可以参与抽奖。而每个功能执行的背后都是通过线程来执行。那么多个任务同时执行也就是常说的多线程。

**串行:**多个程序在一个CPU上排队执行,比如在电影院买票,只有一个窗口,大家按部就班的排队买票(单核CPU上执行程序)

**并行:**多个程序同时在多个CPU上执行。还是买票的例子,买票的人太多了,电影院又开了几个窗口同时买票,效率高了不少。

**并发:**多个程序在一个CPU上运行,CPU在多个程序之间快速切换,微观上不是同时运行,任意一个时刻只有一个程序在运行,但宏观上看起来就像多个程序同时执行。电影院的例子:电影院增加改签服务,同时售票员get一像新技能,即能同时卖票,在出票的同时还能办理改签业务。

**同步:**在发出一个调用时,在没有得到结果之前,该调用就不返回。栗子:在电影院买票的同时,你得等到票出来了才能离开。 异步:在发出一个异步调用后,调用者不会立刻得到结果,该调用就返回了。栗子:退票,售票员处理后,钱会直接退回到你支付宝里,你不用等着领了钱再走。

四.死锁

死锁是导致系统功能不可用的重要原因之一;
什么是死锁呢?
线程1在等待线程2释放锁,线程2也在等线程1释放另一个锁,最终导致线程1和2都在等待中,从而不能继续执行程序;

构成死锁的必要条件有一下几个

互斥
不可剥夺
保持申请
循环等待
互斥:也就是加互斥锁,线程1获取到了对资源1的锁,那么线程2就不能获取对资源1的锁了
不可剥夺 线程1对资源1加的锁,线程2不可以撤销线程1对资源1加的锁
保持申请 线程1一直持有对资源1的锁
循环等待 线程1等线程2 线程2等线程1

在这里插入图片描述
我们可以看到线程1和2都在120行处等待,所以下面的代码不会执行, 这就是死锁

3.1 如何避免死锁呢?

避免一个线程同时获取多个锁
避免一个线程同时占用多个资源
尝试使用定时锁来代替内部的锁机制
对于数据库锁,加锁和解锁必须在同一个连接内,否则解锁会失败

五.多线程需要考虑的问题

即使我们使用了多线程,但是系统还是会受到硬盘的读写速度,网络带宽,cpu处理速度等的影响
所以在设置线程数的时候也要综合考虑

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值