面试题-线程类

1、创建线程的几种方式?

    继承Thread类;实现Runable接口;使用匿名类;实现Callable接口,该接口中的call方法可以在线程执行结束时产生一个返回值

2、实现线程同步的方法?

    同步方法,同步代码块,使用volatile实现线程同步,使用重入锁实现同步,使用局部变量

3、wait和sleep的区别?

    前者释放锁,不会自动唤醒(用notify唤醒);后者不释放锁,会自动唤醒

    sleep()方法(休眠)是线程类(Thread)的静态方法,调用此方法会让当前线程暂停执行指定的时间,将执行机会(CPU)让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复(线程回到就绪状态,请参考第66题中的线程状态转换图)。wait()是Object类的方法,调用对象的wait()方法导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有调用对象的notify()方法(或notifyAll()方法)时才能唤醒等待池中的线程进入等锁池(lock pool),如果线程重新获得对象的锁就可以进入就绪状态。

4、Runable和Callable接口的区别?

    前者方法是run,后者方法是call,前者任务执行后不能返回值,不可以抛出异常,而后者都可以

5、如何实现线程安全?

    不变的对象一定是线程安全的(对象没有变量只有方法,对象创建后状态不能修改,对象的所有变量都是final),实例封闭(将数据封装对象内部,可以将数据的访问限制在对象的方法上),使用同步保证原子性

6、什么是线程局部变量?
    线程局部变量是局限于线程内部的变量,属于线程自身所有,不在多个线程间共享。Java 提供 ThreadLocal 类来支持线程局部变量,是一种实现线程安全的方式。但是在管理环境下(如 web 服务器)使用线程局部变量的时候要特别小心,在这种情况下,工作线程的生命周期比任何应用变量的生命周期都要长。任何线程局部变量一旦在工作完成后没有释放,Java 应用就存在内存泄露的风险。

7、线程的sleep()方法和yield()方法有什么区别?
① sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会;
② 线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态;
③ sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常;
④ sleep()方法比yield()方法(跟操作系统CPU调度相关)具有更好的可移植性。

8、当一个线程进入一个对象的synchronized方法A之后,其它线程是否可进入此对象的synchronized方法B?
    不能。其它线程只能访问该对象的非同步方法,同步方法则不能进入。因为非静态方法上的synchronized修饰符要求执行方法时要获得对象的锁,如果已经进入A方法说明对象锁已经被取走,那么试图进入B方法的线程就只能在等锁池中等待对象的锁。

9、简述synchronized 和java.util.concurrent.locks.Lock的异同?
    Lock是Java 5以后引入的新的API,和关键字synchronized相比主要相同点:Lock 能完成synchronized所实现的所有功能;

    主要不同点:Lock有比synchronized更精确的线程语义和更好的性能,而且不强制性的要求一定要获得锁。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且最好在finally 块中释放(这是释放外部资源的最好的地方)。

10、什么是线程池(thread pool)?
    在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源。在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收。所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁,这就是”池化资源”技术产生的原因。线程池顾名思义就是事先创建若干个可执行的线程放入一个池(容器)中,需要的时候从池中获取线程不用自行创建,使用完毕不需要销毁线程而是放回池中,从而减少创建和销毁线程对象的开销。

猜你喜欢

转载自blog.csdn.net/m0_37524661/article/details/81662166
今日推荐