Java 面试知识点解析(二)——高并发编程篇 (3)

答:阻塞和非阻塞通常用来形容多线程间的相互影响。比如一个线程占用了临界区资源,那么其他所有需要这个而资源的线程就必须在这个临界区中进行等待。等待会导致线程挂起,这种情况就是阻塞。此时,如果占用资源的线程一直不愿意释放资源,那么其他所有阻塞在这个临界区上的线程都不能工作。

非阻塞的意思与之相反,它强调没有一个线程可以妨碍其他线程执行。所有的线程都会尝试不断前向执行。

面试官:临界区是什么?

答:临界区用来表示一种公共资源或者说是共享资源,可以被多个线程使用。但是每一次,只能有一个线程使用它,一旦临界区资源被占用,其他线程要想使用这个资源,就必须等待。

比如,在一个办公室里有一台打印机,打印机一次只能执行一个任务。如果小王和小明同时需要打印文件,很显然,如果小王先下发了打印任务,打印机就开始打印小王的文件了,小明的任务就只能等待小王打印结束后才能打印,这里的打印机就是一个临界区的例子。

在并行程序中,临界区资源是保护的对象,如果意外出现打印机同时执行两个打印任务,那么最可能的结果就是打印出来的文件就会是损坏的文件,它既不是小王想要的,也不是小明想要的。

6)什么是死锁(Deadlock)、饥饿(Starvation)和活锁(Livelock)?

答:死锁、饥饿和活锁都属于多线程的活跃性问题,如果发现上述几种情况,那么相关线程可能就不再活跃,也就说它可能很难再继续往下执行了。

Java 面试知识点解析(二)——高并发编程篇

死锁应该是最糟糕的一种情况了,它表示两个或者两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

饥饿是指某一个或者多个线程因为种种原因无法获得所需要的资源,导致一直无法执行。比如:
1)它的线程优先级可能太低,而高优先级的线程不断抢占它需要的资源,导致低优先级的线程无法工作。在自然界中,母鸡喂食雏鸟时,很容易出现这种情况,由于雏鸟很多,食物有限,雏鸟之间的食物竞争可能非常厉害,小雏鸟因为经常抢不到食物,有可能会被饿死。线程的饥饿也非常类似这种情况。
2)另外一种可能是,某一个线程一直占着关键资源不放,导致其他需要这个资源的线程无法正常执行,这种情况也是饥饿的一种。
与死锁相比,饥饿还是有可能在未来一段时间内解决的(比如高优先级的线程已经完成任务,不再疯狂的执行)

活锁是一种非常有趣的情况。不知道大家是不是有遇到过这样一种情况,当你要坐电梯下楼,电梯到了,门开了,这时你正准备出去,但不巧的是,门外一个人挡着你的去路,他想进来。于是你很绅士的靠左走,避让对方,但同时对方也很绅士,但他靠右走希望避让你。结果,你们又撞上了。于是乎,你们都意识到了问题,希望尽快避让对方,你立即向右走,他也立即向左走,结果又撞上了!不过介于人类的只能,我相信这个动作重复 2、 3 次后,你应该可以顺利解决这个问题,因为这个时候,大家都会本能的对视,进行交流,保证这种情况不再发生。
但如果这种情况发生在两个线程间可能就不会那么幸运了,如果线程的智力不够,且都秉承着 “谦让” 的原则,主动将资源释放给他人使用,那么就会出现资源不断在两个线程中跳动,而没有一个线程可以同时拿到所有的资源而正常执行。这种情况就是活锁。

7)多线程产生死锁的 4 个必要条件?

答:

互斥条件:一个资源每次只能被一个线程使用;

请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放;

不剥夺条件:进程已经获得的资源,在未使用完之前,不能强行剥夺;

循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系。

面试官:如何避免死锁?(经常接着问这个问题哦~)

答:指定获取锁的顺序,举例如下:

比如某个线程只有获得 A 锁和 B 锁才能对某资源进行操作,在多线程条件下,如何避免死锁?

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzdwjz.html