「这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战」
兄弟们,今天国际惯例,给自己充电,充什么内容那?听说能够现在流行是并发+数据结构与算法(懂我意思嘛,现在弄并发,弄完并发弄数据结构,挖个坑埋点土,数个12345,哈哈哈哈),既然它流行肯定是有它的道理的,咱们话不多说,先整点并发基础知识,来玩一玩!(悄悄告诉兄弟们,就10个点哦,加油哦!)
什么是线程,什么是进程?
进程就是一次程序的执行过程,是操作系统调用程序的基本单位,它也是动态的;程序的一次执行过程就是进程的从创建到执行在销毁的过程!
举个例子,window的任务管理器当中的.exe都是进程!
线程跟进程类似,线程是比进程更小的执行单位,一个进程可能包含多个线程,而进程和线程不同的是同类的线程包含的堆和方法区是共享的,只有虚拟机栈,本地方法栈,程序计数器才是每个线程私有的!
线程和进程的区别与优缺点
线程是进程更小的执行单元,而他们最大的区别就是进程之间是相互独立的,而线程不一定,同一个进程当中的线程可能会相互影响;因为线程的执行开销比进程小,所以不利于资源的管理与维护,而进程相反!
(哎呦,看这篇文章的朋友,真是太棒了!不仅能坚持看文章,还了解了线程和进程,我丢!可以)
为什么程序计数器,本地方法栈,虚拟机栈是私有的那?
我们先讨论程序计数器,程序计数器主要有两大功能:
1、字节码解释器会通过改变程序计数器来改变指令的读取顺序,从而控制流程,比如:顺序执行,选择,循环等等
2、多线程情况下,程序计数器会记录当前线程的执行位置,从而在切换回来的时候知道执行到哪里了!
如果程序计数器是共享的,则那个是线程是当前线程那,当发生上下文切换的时候,怎么切换回来那?所以说只能是私有的!
我们再来讨论一下本地方法栈,本地方法栈是干什么用的那?
当Java方法在执行的时候会创建一个栈帧,用来存储局部变量,操作数栈,常量池,执行一个方法的过程就是栈帧的入栈和出栈的过程,所以说本地方法栈是用来存放栈帧的。
假如 本地方法栈是共享的,则栈帧也是共享的,而栈帧包含局部变量,啊!局部 变量竟然共享了,这肯定是不行的!所以本地方法栈也是私有的!
最后讨论一下虚拟机栈, 它其实和本地方法栈的作用是一样的,只不过是不是java方法,而是native方法!所以也是不能共享的!
一句话简单了解堆和方法区
堆和方法区都是线程共享的区域,堆主要存放的是所有新建的对象,而方法区主要存放的是已经创建好的类信息,常量,静态变量等信息!
说说并行与并发的区别
- 并行:单位时间内,多个任务同时执行(同时执行!)
- 并发:某个时间段内,多个任务都在执行(交替执行!)
为什么要使用多线程?
- 从当前互联网所处的环境来讲,动不动上十万,上百万,上千万的并发量,单线程怎么可能支撑住!多线程又是并发的基础,所以多线程是非常重要的!(关于线程其实也有很多要说的,比如线程的创建方式,线程池的参数等等!关注不迷路,后期必出!)
- 从计算机的底层来讲,线程是属于轻量级的进程,多个线程的切换比进程切换开销小多了,如果是单核CPU提高的是CPU的综合利用率,比如只有一个线程,CPU计算的时候,IO空闲,IO忙的时候,CPU空闲,多个CPU可以综合提高他们的利用率,虽然是切换执行,但是最起码不会让他们空闲!如果是多核CPU,一个核能只能调用一个线程,如果只有一个线程那其他核不就空闲了,利用率太低了,所以多线程可以提高CPU的利用率!
多线程会遇到什么问题?
多线程固然很多可以提高资源的利用率,还可以提高程序的执行效率及速度,但是高的并发量会带来很多的问题,比如死锁,线程不安全,内存泄漏等等!
线程的生命周期和状态有那些?
| 状态名称 | 状态描述 |
|---|---|
| NEW | 初始状态,线程刚刚被创建,但是还没有start() |
| RUNNABLE | 运行状态,已经调用start(),线程处于就绪状态或者运行中状态 |
| BLOCKED | 线程进入阻塞的状态 |
| WAITING | 线程进入等待的状态,需要调用notify()或者notifyall()才能被唤醒! |
| TIME_WATING | 超时等待,超过时间后自动被唤醒 |
| TERMINATED | 终止状态,线程执行完毕之后的状态 |
什么是上下文切换?
一句话就是任务从保存再到加载的过程,这就算是一次上下文切换! 略微详细点说就是,任务开始执行后,时间片到期后先保存当前状态,以便切换回来的时候知道进行到哪里了,然后切换到其他的任务当中。
什么是线程死锁,如何预防和避免死锁?
线程死锁就是多个线程陷入阻塞状态,都在等待对方所有的持有的资源!比如,线程A持有资源A,还需要资源B,线程B持有资源B,但是还需要资源A,那等着吧,都不释放,这就陷入了死锁!
死锁产生的四大条件:
- 互斥条件:一个资源在一个时刻只能被一个线程持有!
- 请求保持条件:线程A请求资源B,会对资源A保持不放!
- 不剥夺条件:当线程A请求资源B,发现资源B被其他线程持有,不可以强行剥夺!
- 循环等待条件:线程A等待线程B的持有资源,线程B等待线程A的持有资源,从而形成环!
如何预防死锁? 思想很简单,就是破坏死锁产生的条件即可!
- 破坏请求保持条件:当申请不到资源的时候,可以释放自己所持有的资源!
- 破坏不剥夺条件:设置优先级,根据优先级来设置是否可以剥夺资源!
- 破坏循环等待条件:按照某种顺序来申请资源或者释放资源!
如何避免死锁? 在进行资源分配的时候,利用算法(银行家算法,后期补充一下,不要慌!)进行资源分配,使得进入安全状态!
sleep()和wait()方法的区别和共同点有哪些?
共同点:都会让线程暂停执行! 区别:
sleep()抱着锁睡觉,wait()会释放锁,之后在睡觉sleep()会自动醒,使线程进入就绪状态,而wait()必须有其他线程调用当前线程的notify()或者notifyall()方法才能够进入就绪状态sleep()一般用于暂停执行,wait()一般用户多个线程之间的交互与通信!
为什么调用start()方法,会执行run()方法,为什么不直接执行run()方法?
这其实非常的简单,调用start()方法会执行线程的准备工作,然后自动执行run()方法,并且线程进入了就绪状态,当分配到时间片后就可以执行了!这才叫多线程!如果直接调用run()方法,就相当于单线程了,跟普通方法有什么区别那!他不会在开一个线程去执行run()方法,而是当前线程直接就执行了!
总结一下,以后要填的坑,并发,多线程,避免死锁的算法,数据结构与算法!先谢谢各位看官老爷的三连及关注!(不会吧,不会吧,不会谢了之后还不三连把!)
感谢大家的阅读,我是Alson_Code,一个喜欢把简单问题复杂化,把复杂问题简单化的程序猿! ❤
参考:JavaGuide的java学习指南!