多线程面试题

1、 sleep、join() 、yiled() 的区别

      sleep:让线程睡眠指定时间, 会释放cpu时间片

       join: 本质是wait/notify, 让线程的执行结果可见

       yiled 让出时间片.触发重新调度.; 作用效果和sleep(0)一样,触发一次切换

2.wait和sleep的区别

       sleep()方法是Thread类的静态方法,是线程用来控制自身流程的,他会使此线程暂停执行一段时间,而把执行机会让给其他线程,等到计时时间一到,此线程会自动苏醒.而wait()方法是object类的方法,用于线程间通信,这个方法会使当前拥有该对象锁的进程等待,直到其他线程调用notify()方法或者notifyAll()时才醒来,不过开发人员也可以给他指定一个时间,自动醒来。

       对锁的 处理机制不同。由于sleep()方法的主要作用是让线程暂停执行一段时间,时间一到则自动恢复,不涉及线程间的通信,因此,调用sleep()方法并不会释放锁。而wait()方法则不同,当调用wait()方法后,线程会释放掉他所占用的锁,从而使线程所在对象中的其他synchronized数据可以被其他线程使用。

     使用区域不同。wait()方法必须放在同步控制方法和同步代码块中使用,sleep()方法则可以放在任何地方使用。sleep()方法必须捕获异常,而wait()、notify()、notifyAll()不需要捕获异常。在sleep的过程中,有可能被其他对象调用他的interrupt(),产生InterruptedException。由于sleep不会释放锁标志,容易导致死锁问题的发生,因此一般情况下,推荐使用wait()方法\

2.线程通信的几种方式

 一、  使用同一个共享变量控制:  Synchronized、join(wait、notify) wait、notify、Lock、Condition   利用volatile   利用AtomicInteger

二、PipedInputStream、PipedOutputStream

三、利用BlockingQueue

四、利用LockSupport---->park()和unpark(thread)

  1. 当调用unpark(thread)方法,就会将thread线程的许可permit设置成1(注意多次调用unpark方法,不会累加,permit值还是1)。
  2. 当调用park()方法,如果当前线程的permit是1,那么将permit设置为0,并立即返回。如果当前线程的permit是0,那么当前线程就会阻塞,直到别的线程将当前线程的permit设置为1.park方法会将permit再次设置为0,并返回。

五、利用ThreadLocal

2、Java中能够创建volatile数组吗?

     可以创建, Volatile 对于引用可见,对于数组中的元素不具备可见性。

 3、++操作是线程安全的吗?

      不是线程安全的, 原子性、有序性、可见性。++操作无法满足原子性

4、线程什么时候会抛出InterruptedException()

       t.interrupt() 去中断一个处于阻塞状态下的线程时(join/sleep/wait

5、Java RunnableCallable有什么相同和区别

   相同点:1)都是接口;2)都可以编写多线程程序;3)都采用Thread.start()启动线程

   不同点:1)Runnable没有返回值;Callable可以返回执行结果,是个泛型,和Future、FutureTask配合可以用来获取异步执行的结果

                 2)Callable接口的call()方法允许抛出异常;Runnable的run()方法异常只能在内部消化,不能往上继续抛

                     注:Callalble接口支持返回执行结果,需要调用FutureTask.get()得到,此方法会阻塞主进程的继续往下执行,如果不调用不会阻塞

7. 有T1/T2/T3三个线程,如何确保他们的执行顺序

    方法一: 在主线程中直接通过 join() 调用

   方法二:先启动最后一个T3,然后T3中调用T2,T2中调用T1

8.Java内存模型是什么?

   JMM是一个抽象的内存模型。它定义了共享内存中多线程程序读写操作的行为规范:在虚拟机中把共享变量存储到内存以及从内  存中取出共享变量的底层实现细节。通过这些规则来规范对内存的读写操作从而保证指令的正确性,它解决了CPU多级缓存、处理器优化、指令重排序导致的内存访问问题,保证了并发场景下的 可见性。

9.什么是线程安全

   原子性、有序性、可见性(硬件层面(CPU高速缓存、指令重排序、JMM))

10 死锁

         条件:1、互斥条件    2、请求与维持    3、不掠夺   4、循环等待

11.hashtable

    hashtable 底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低.

12.ConcurrentHashMap 

   1).是 J.U.C 包里面提供的一个线程安全并且高效的 HashMap

   2)在 JDK1.7由一个个 Segment 组成,通过继承 ReentrantLock 来进行加锁,采用的分段锁,通过每次锁住一个 segment 来保证每个segment 内的操作的线程安全性。每个segment  都有一个hashEntry[] ,冲突健进行链式分布。 

   3)JDK1.8 相比于 1.7 版本,它做了两个改进

  •        取消了 segment 分段设计,直接使用 Node 数组来保存数据,并且采用 Node 数组元素作为锁来 实现每一行数据进行加锁来进一步减少并发冲突的概率
  •        将原本数组+单向链表的数据结构变更为了数组+单向链表+红黑树的结构。 

        为什么要引入红黑树呢?

           在正常情况下,key hash 之后如果能够很均匀的分散在数组中,那么table 数组中的每个队列的长度主要为 0 或者 1.但是实际情况下,还是会存在一些队列长度过长的情况。如果还采用单向列表方式,那么查询某个节点的时间复杂度就变为 O(n); 因此对于队列长度超过 8 的列表,JDK1.8 采用了红黑树的结构,那么查询的时间复杂度就会降低到O(logN),可以提升查找的性能;

      多线程面试题_第1张图片                 多线程面试题_第2张图片

  


 

你可能感兴趣的:(面试知识点,Java多线程)