多线程面试题(史上最全、持续更新、吐血推荐) (10)

线程调度程序从可运行池中选择一个线程作为当前线程时线程所处的状态。这也是线程进入运行状态的唯一的一种方式。

3. 阻塞状态(BLOCKED)

阻塞状态是线程阻塞在进入synchronized关键字修饰的方法或代码块(获取锁)时的状态。

4. 等待(WAITING)

处于这种状态的线程不会被分配CPU执行时间,它们要等待被显式地唤醒,否则会处于无限期等待的状态。

5. 超时等待(TIMED_WAITING)

处于这种状态的线程不会被分配CPU执行时间,不过无须无限期等待被其他线程显示地唤醒,在达到一定时间后它们会自动唤醒。

6. 终止状态(TERMINATED)

当线程的run()方法完成时,或者主线程的main()方法完成时,我们就认为它终止了。这个线程对象也许是活的,但是它已经不是一个单独执行的线程。线程一旦终止了,就不能复生。

在一个终止的线程上调用start()方法,会抛出java.lang.IllegalThreadStateException异常。

三:synchronized同步面试题 1. synchronized的简介

synchronized要理解为加锁,而不是锁,这个思维有助于你更好的理解线程同步。

1.1 synchronized的使用及各自的锁对象

这里简要介绍一下,为以后的内容做一下铺垫:

普通方法 :锁对象是this,所谓的方法锁(本质上属于对象锁)

public synchronized void say(){ System.out.println("Hello,everyone..."); }

同步代码块(方法中):锁对象是synchronized(obj)的对象,所谓的对象锁

public void say(boolean isYou){ synchronized (obj){ System.out.println("Hello"); } }

同步静态方法:锁对象是当前类的Class对象,即(XXX.class),所谓的类锁

public static synchronized void work(){ System.out.println("Work hard..."); }

希望大家再遇到对象锁,类锁而不知所措…有时候遇到面试官把问题描述的不够清楚时,要勇于及时和面试官沟通。虽然找工作时总会遇到奇葩面试官,但是如果你遇到的几率太高时,请自觉地审视一下自己…

1.2 synchronized的关于代码块的疑问

看到上面synchronized的用法,你会有这样的疑问吗?synchronized能修饰类级别(静态)代码块吗?(PS: 这个话题是我临时想起的,改天在面试中问一下看看效果…)

结论:synchronized不能用在类级别的(静态)代码块

如果在面试中不给你编译器,大多数人估计都是要mountain泰吧。这里直接给出我的理解:

这个要从加载顺序上考虑。
类级别的代码块在加载顺序上是要优先于任何方法的,其执行顺序只跟代码位置先后有关。没人跟你抢,自然不需要同步。

2. 涉及synchronized的面试题

这里通过一个常见的面试题-单例模式来展开,这篇文章主要内容是考察synchronized关键字的,就直奔主题进入DCL(Double Check Lock)双重校验锁的单例。

2.1 围绕着DCL展开的话题 2.1.1 实现DCL

如果DCL不懂,就尴尬无止境啦…。感兴趣的可以去看一下《Java高并发核心编程(卷2)》

public class SingleInstance { private volatile static SingleInstance instance = null; private SingleInstance(){ } public static SingleInstance getInstance(){ if (instance == null){ synchronized (SingleInstance.class){ if (instance == null){ instance = new SingleInstance(); } } } return instance; } } 2.1.2 谈一下synchronized的作用

synchronized 关键字主要用来解决的是多线程同步问题,其可以保证在被其修饰的代码任意时刻只有一个线程执行。视情况而定,(主动)说出它的用法及底层实现原理(使用的是moniterenter 和 moniterexit指令…),PS:synchronized的底层实现原理会单独展开…

2.1.3 这里(DCL)的volatile的作用

volatile只能保证变量的可见性,并不能保证对volatile修饰的变量的操作的原子性。

volatile的主要作用:

保持内存可见性;使所有线程都能看到共享内存的最新状态。

防止指令重排的问题;

通过设置内存屏障实现的。感兴趣的可以去看一下《Java高并发核心编程(卷2)》

个人拙见,能答出来上面的内容即可,更深入的绝大部分都是在SHOW或者就是压薪资…

2.2 基础面试点

为了节约各位看官的时间,先把结论给出来:

若是对象锁,则每个对象都持有一把自己的独一无二的锁,且对象之间的锁互不影响 。若是类锁,所有该类的对象共用这把锁。

一个线程获取一把锁,没有得到锁的线程只能排队等待;

synchronized 是可重入锁,避免很多情况下的死锁发生。

synchronized 方法若发生异常,则JVM会自动释放锁。

锁对象不能为空,否则抛出NPE(NullPointerException)

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

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