JAVA并发最最最最最最基础知识

109 阅读8分钟

「这是我参与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学习指南!