Java并发编程基础

###1.什么是线程和进程?
   1.进程就是程序的一次执行过程,是动态的,是系统运行程序的基本单位。系统运行一个程序即是进程从创建到运行再到销毁的过程。
   2.一个进程有多个线程,线程是比进程还小的执行单位,因此线程又称为轻量级进程。线程共享进程的堆和方法区,但是有自己独有的虚拟机栈和程序计数器以及本地方法栈。
###2.请简要描述线程与进程的关系,区别及优缺点?
   1.线程是比进程更小的执行单位,并且线程共享进程中的方法区(JDK1.8之后被改成是元空间)和堆,线程有自己私有的本地方法栈,虚拟机栈以及程序计数器,但是线程之间会相互的影响但是进程是独立的,而且线程执行开销下,但是不利于资源的管理和保护,进程却恰恰相反。
###3.程序计数器为什么是私有的?
   2.程序计数器作用:
      1.字节码解释器可以通过改变程序计数器来依次读取指令,从而实现
代码的流程控制。如:顺序执行,选择,循环,异常处理。
      2.在多线程的情况下,程序计数器用来记录当前线程执行的位置,从而当线程切换回来的时候可以知道该线程上次运行到哪里。需要注意的是,当运行的方法是native方法的时候,程序计数器中记录的是undefined位置,只有在运行Java代码的时候程序计数器中的记录才是当前线程上次运行的位置(下一条指令的地址)。
      3.因此,程序计数器是私有的原因就是为了线程切换之后能恢复到正确的执行位置。
###4.虚拟机栈和本地方法栈为什么是私有的?
   1.虚拟机栈:每个Java方法在执行的时候都会同时创建一个栈帧来存储局部变量表、操作数栈、常量池引用等信息,从方法的调用到执行完成的过程都对应栈桢在虚拟机栈中入栈和出栈的过程。
   2.本地方法栈和虚拟机栈的作用是差不多的,两者的区别是虚拟机栈是为虚拟机中执行Java方法服务而本地方法栈则是为虚拟机执行native方法服务。,在HotSpot虚拟机中其将本地方法栈合并到虚拟机栈中去。
   2.因此,虚拟机栈和本地方法栈私有的原因是:为了线程中的局部变量不被其他线程所访问。
###5.一句话简单了解堆和方法区
   1.堆和方法区是所有线程共享的区域,堆是进程中最大的一块内存,用来存放新创建的对象(所有对象都在这里分配内存),方法区主要用来存放已经被加载的类信息,常量,静态变量,即时编译器编译之后的代码等数据。
###6.说说并发与并行的区别?
   并发是一段时间内多个任务同时发生(同一时间段,多个任务都在执行,单位时间内,不一定同时执行);并行是在时间点上多个任务同时发生(单位时间内,多个任务同时执行)。
###7.为什么要使用多线程呢?
   1.从计算机底层来说:线程是轻量级的线程,是程序执行的最小单位,线程间切换和开销,调度的成本比进程小的多,另外多核CPU的时代的到来意味着多个线程可以同时执行,减少了线程上下文切换的开销。
   2.从互联网的发展趋势来看:现在的系统动不动就百万级,千万级的并发量,多线程并发编程为开发高并发的应用提供了良好的基础,并且多线程机制可以大大提高整个系统的并发能力和性能。
   3.再深入计算机底层来说:
      单核时代:多线程的开发主要是提高CPU和IO设备的综合利用率。一个线程执行CPU计算+另一个线程进行IO操作 = 100%的综合利用率。
      多核时代:多线程主要是为了提高CPU的利用率,由于多核CPU(多个计算机内核的中央处理器,也就是一枚处理器中集成两个或多个完整的计算引擎(内核))的出现,创建多个线程可以让多个CPU核心被利用到,这样就能提高CPU的利用率。
###8.使用多线程可能带来什么问题?
   1.并发编程主要是为了提高程序的执行效率(运行速度),但是并发编程并不总是能提高程序的执行效率(运行速度),而且并发编程还会遇到很多问题,比如:内存泄漏,上下文切换、死锁还有受限于硬件和软件的资源闲置问题。
###9.说说线程的生命周期和状态?
   1.NEW:新建状态:初始状态,线程被构建但是还没有调用start()
   1.RUNNABLE:运行状态:JAVA线程将操作系统中的就绪状态和运行状态统称为运行中
   1.BLOCKED:阻塞状态;线程阻塞于锁
   1.WAITING:等待状态;线程进入等待状态,进入该状态表示当前线程需要等待其它线程执行完成之后才能继续运行
   1.TIME_WAITING:超时等待状态;该状态不同于WAITING的区别在于,等待时间到了之后会自行返回运行状态
   1.TERMINATED:终止状态:表示线程已经执行完毕

###10.什么是上下文切换?
   1.当前任务执行完CPU时间片切换到另一个任务之前会先保存自己的状态,以便下次再切换回来之后可以加载到这个任务的状态。也就是任务从保存到加载的过程就是一次上下文切换。
   2.Lunix相比其他操作系统,它的上下文切换和模式切换消耗的时间比较少。
   详细来说就是当一个线程的时间片用完的时候就会重新处于就绪状态让给其他的线程使用,这个过程就是上下文切换。
###11.什么是线程死锁?如何避免死锁?
   1.线程死锁就是多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放,因此由于线程被无限期地阻塞,因此程序不可能正常终止。

   2.产生死锁的四个条件:
      1.互斥条件:该资源任意时刻只由一个线程占用;
      2.请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放。
      3.不剥夺条件:线程以获取的资源在未使用完之前不能被其它线程强行剥夺,只有自己使用完毕之后才能释放资源。
      4.循环等待条件:若干线程之间形成一种头尾相接的循环等待资源的关系。
###12.如何避免线程死锁?
   我们只要破坏产生死锁的四个条件中的其中一个就可以了。
      1.破坏互斥条件:这个条件我们是没有办法破坏的,因为我们用锁本来就是想让他们互斥的(临界资源需要互斥访问)。
      2.破坏请求与保持条件:一次性申请所有的资源。
      3.破坏不剥夺条件:占用部分资源的线程进一步申请其它资源的时候,如果申请不到可以主动释放它占用的资源。
      4.破坏循环等待条件:靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。破坏循环等待条件。
###13.说说sleep()方法和wait()方法区别和共同点?
   1.两者的主要区别就是sleep()方法没有释放锁,而wait方法释放了锁。
   2.两者都可以暂停线程的执行。
   3.wait()方法通常被用于线程间交互/通信,sleep()通常被用于暂停执行。
   4.wait()方法被调用后,线程不会自动苏醒,需要别的线程调用同一对象上的notify()方法或者notifyAll()方法。sleep()方法执行完成后,线程会自动苏醒。
###14.为什么我们调用start()方法时会执行run()方法,为什么我们不能直接调用run()方法?
   new一个Thread,线程进入了新建状态,调用start()方法,会启动一个线程并使线程进入了就绪状态,当分配到时间片后就可以开始运行了。start()会执行线程相应的准备工作,然后自动执行run()方法中的内容,这是真正的多线程工作。而直接执行run()方法,会把run()方法当作一个main线程下的普通方法去执行,并不会在某个线程中执行它,所以这并不是多线程工作。
   总结:调用start方法方可启动线程并使线程进入就绪状态,而run方法只是thread的一个普通方法调用,还是在主线程里执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值