面试对线记录14 多线程基础

前几天面了两个面试官,有一些基础的东西还是记得不太清楚,在这里记录一下

  1. 线程和进程
    线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。
    进程是计算机重的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
  2. 创建线程的方式
    继承Thread重写run方法;实现Runnable接口或者Callable接口;这两个接口的区别,就是Runable没有返回值,而callable有返回值。
  3. sleep和wait的区别
    sleep()继承自Thread,wait()继承自Object;sleep不会释放锁,wait()会释放锁,sleep()函数时间到的时候会自动恢复;而wait()函数可以使用notify()或者noitfyAll()函数直接唤醒;
  4. notify()和notifyAll()有什么区别
    notifyAll()调用后会将全部线程由等待池移动到锁池,然后参与锁的竞争,竞争成功就会继续执行,如果不成功就会留在锁池等待锁被释放后再次参与竞争,而notify()只会唤醒一个线程,具体唤醒哪个就需要看虚拟机了。
  5. run()和start()有什么区别
    start()方法用于启动线程,run()方法用于执行线程的运行时代吗,run()可以重复调用,而start()只能调用一次。
  6. 什么是死锁 如果线程A持有独占锁a,并尝试去获取独占锁b的同时,线程B持有独占锁b,并尝试获取独占锁a的情况下,就会发生AB两个线程由于2互相持有对方需要的锁,而发生的阻塞现象。
  7. 如何避免思索
  • 尽量使用tryLock方法,设置超时时间,超时可以退出死锁;
  • 尽量使用java.util.concurrent并发累代替自己手写锁;
  • 尽量降低锁的使用粒度,尽量不要几个功能使用同一把锁;
  • 尽量减少同步的代码块;
  1. synchronized底层实现 synchronized是由monitorenter和monitorexit实现的。monitor对象是对象同步的基本单元,在Java6之前的话monitor主要是依靠操作系统内部的互斥锁实现的,因为需要进行用户态和内核态的切换,所以同步操作是一个无差别的重量级操作,性能很低;在Java6之后,Java虚拟机优化了moitor的实现,提供了三种不同的锁:偏向锁,轻量级锁和重量级锁,大大改进了它的性能。
  2. synchronized和volatile的区别 volatile是变量修饰符,synchronized是修饰类,方法和代码段;
    volatile仅能实现变量的修改可见性,不能保证原子性;synchronized可是保证变量修改的可见性和原子性;
    volatile不会造成线程的阻塞,synchronized可能会造成线程的阻塞;
  3. synchronized和ReentrantLock的区别 ReentrantLock使用起来比较灵活,但是需要手动释放锁;
    synchronzied 不需要手动释放和开启锁,但是他比ReentrantLock大多数场景都性能相差很大,但是Java6对synchronized进行了很多的改进;
    ReentrantLock只适用于代码块锁,而synchronized可用于修饰方法和代码块等等。