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

同步本身是不具备继承性的:即父类的synchronized 方法,子类重写该方法,分情况讨论:没有synchonized修饰,则该子类方法不是线程同步的。(PS :涉及同步继承性的问题要分情况)

synchronized本身修饰的范围越小越好。毕竟是同步阻塞。跑不快还占着超车道…

2.2.1 同时访问synchronized的静态和非静态方法,能保证线程安全吗?

结论:不能,两者的锁对象不一样。前者是类锁(XXX.class),后者是this

2.2.2 同时访问synchronized方法和非同步方法,能保证线程安全吗?

结论:不能,因为synchronized只会对被修饰的方法起作用。

2.2.3 两个线程同时访问两个对象的非静态同步方法能保证线程安全吗?

结论:不能,每个对象都拥有一把锁。两个对象相当于有两把锁,导致锁对象不一致。(PS:如果是类锁,则所有对象共用一把锁)

2.2.4 若synchronized方法抛出异常,会导致死锁吗?

JVM会自动释放锁,不会导致死锁问题

2.2.5 若synchronized的锁对象能为空吗?会出现什么情况?

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

2.2.6 若synchronized的锁对象能为空吗?会出现什么情况?

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

2.3 关于继承性的面试点 2.3.1 synchronized涉及的继承性问题

重写父类的synchronized的方法,主要分为两种情况:

子类的方法没有被synchronized修饰:

synchronized的不具备继承性。所以子类方法是线程不安全的。

子类的方法被synchronized修饰(这里面试点主要考察锁对象的归属问题):

两个锁对象其实是一把锁,而且是子类对象作为锁。这也证明了: synchronized的锁是可重入锁。否则将出现死锁问题。

2.4 实战经验的面试点 2.4.1 在开发过程中,你经常使用synchronized方法多还是synchronized代码块?and why?

关于synchronized 的内容部分,我在面试过程中经常问且只问这一道题。本人认为这个能很好的考察面试者的综合素质。(PS:毕竟是要拧螺丝的…)

synchronized同步的范围是越小越好。因为若该方法耗时很久,那其它线程必须等到该持锁线程执行完才能运行。(黄花菜都凉了都…)
而synchronized代码块部分只有这一部分是同步的,其它的照样可以异步执行,提高运行效率。

3、对象锁的同步队列

当前线程想调用对象A的同步方法时,发现对象A的锁被别的线程占有,此时当前线程进入对象锁的同步队列。简言之,同步队列里面放的都是想争夺对象锁的线程。

当一个线程1被另外一个线程2唤醒时,1线程进入同步队列,去争夺对象锁。

同步队列是在同步的环境下才有的概念,一个对象对应一个同步队列。

线程等待时间到了或被notify/notifyAll唤醒后,会进入同步队列竞争锁,如果获得锁,进入RUNNABLE状态,否则进入BLOCKED状态等待获取锁。

4、 如何在两个线程间共享数据?

你可以通过共享对象来实现这个目的,或者是使用像阻塞队列这样并发的数据结构。这篇教程《Java线程间通信》(涉及到在两个线程间共享对象)用wait和notify方法实现了生产者消费者模型。

5、 Java中notify 和 notifyAll有什么区别?

这又是一个刁钻的问题,因为多线程可以等待单监控锁,Java API 的设计人员提供了一些方法当等待条件改变的时候通知它们,但是这些方法没有完全实现。notify()方法不能唤醒某个具体的线程,所以只有一个线程在等待的时候它才有用武之地。而notifyAll()唤醒所有线程并允许他们争夺锁确保了至少有一个线程能继续运行。

6) 为什么wait, notify 和 notifyAll这些方法不在thread类里面?

一个很明显的原因是JAVA提供的锁是对象级的而不是线程级的,每个对象都有锁,通过线程获得。如果线程需要等待某些锁那么调用对象中的wait()方法就有意义了。如果wait()方法定义在Thread类中,线程正在等待的是哪个锁就不明显了。简单的说,由于wait,notify和notifyAll都是锁级别的操作,所以把他们定义在Object类中因为锁属于对象。

7) 为什么wait和notify方法要在同步块中调用?

当一个线程需要调用对象的wait()方法的时候,这个线程必须拥有该对象的锁,接着它就会释放这个对象锁并进入等待状态直到其他线程调用这个对象上的notify()方法。同样的,当一个线程需要调用对象的notify()方法时,它会释放这个对象的锁,以便其他在等待的线程就可以得到这个对象锁。由于所有的这些方法都需要线程持有对象的锁,这样就只能通过同步来实现,所以他们只能在同步方法或者同步块中被调用。如果你不这么做,代码会抛出IllegalMonitorStateException异常。

8) 为什么应该在循环中检查等待条件?

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

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