美文网首页2019年JAVA面试 问题总结
java并发面试题总结(1~20题)

java并发面试题总结(1~20题)

作者: WinkTink | 来源:发表于2019-05-12 15:02 被阅读46次

1.  ThreadLocal(线程变量副本)?

Synchronized实现内存共享,ThreadLocal为每个线程维护一个本地变量。

采用空间换时间,它用于线程间的数据隔离,为每一个使用该变量的线程提供一个副本,每个线程都可以独立地改变自己的副本,而不会和其他线程的副本冲突。

ThreadLocal类中维护一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值为对应线程的变量副本。

ThreadLocal在Spring中发挥着巨大的作用,在管理Request作用域中的Bean、事务管理、任务调度、AOP等模块都出现了它的身影。

Spring中绝大部分Bean都可以声明成Singleton作用域,采用ThreadLocal进行封装,因此有状态的Bean就能够以singleton的方式在多线程中正常工作了。

友情链接:深入研究java.lang.ThreadLocal类

2. Synchronized关键字、Lock,并解释它们之间的区别?

       Synchronized 与Lock都是可重入锁,同一个线程再次进入同步代码的时候.可以使用自己已经获取到的锁

       Synchronized是悲观锁机制,独占锁。而Locks.ReentrantLock是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。 ReentrantLock适用场景

       某个线程在等待一个锁的控制权的这段时间需要中断

       需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程,锁可以绑定多个条件。

       具有公平锁功能,每个到来的线程都将排队等候。

友情链接: Synchronized关键字、Lock,并解释它们之间的区别

3. fail-fast是什么?

        fail-fast机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。

        例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件

4. 聊聊happens-before?

       如果两个操作之间具有happens-before 关系,那么前一个操作的结果就会对后面一个操作可见。

       1)程序顺序规则:一个线程中的每个操作,happens- before 于该线程中的任意后续操作。

       2)监视器锁规则:对一个监视器锁的解锁,happens- before 于随后对这个监视器锁的加锁。

       3)volatile变量规则:对一个volatile域的写,happens- before于任意后续对这个volatile域的读。

       4)传递性:如果A happens- before B,且B happens- before C,那么A happens- before C。

       5)线程启动规则:Thread对象的start()方法happens- before于此线程的每一个动作。

5. Volatile和Synchronized四个不同点?

        1)粒度不同,前者针对变量 ,后者锁对象和类

        2)syn阻塞,volatile线程不阻塞

        3)syn保证三大特性,volatile不保证原子性

        4)syn编译器优化,volatile不优化 volatile具备两种特性:

1.保证此变量对所有线程的可见性,指一条线程修改了这个变量的值,新值对于其他线程来说是可见的,但并不是多线程安全的。

2.禁止指令重排序优化。

6. Volatile如何保证内存可见性?

1.当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存。

2.当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效。线程接下来将从主内存中读取共享变量。

7.  同步、异步、阻塞、非阻塞是什么?

同步:就是一个任务的完成需要依赖另外一个任务,只有等待被依赖的任务完成后,依赖任务才能完成。

异步:不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,只要自己任务完成了就算完成了,被依赖的任务是否完成会通知回来。(异步的特点就是通知)。 打电话和发短信来比喻同步和异步操作。

阻塞:CPU停下来等一个慢的操作完成以后,才会接着完成其他的工作。

非阻塞:非阻塞就是在这个慢的执行时,CPU去做其他工作,等这个慢的完成后,CPU才会接着完成后续的操作。非阻塞会造成线程切换增加,增加CPU的使用时间能不能补偿系统的切换成本需要考虑。

友情链接:Java并发编程之volatile关键字解析

8.  线程之间如何通信的?

        线程的通信是指线程之间以何种机制来交换信息。在编程中,线程之间的通信机制有两种,共享内存和消息传递。

        在共享内存的并发模型里,线程之间共享程序的公共状态,线程之间通过写-读内存中的公共状态来隐式进行通信,典型的共享内存通信方式就是通过共享对象进行通信。

        在消息传递的并发模型里,线程之间没有公共状态,线程之间必须通过明确的发送消息来显式进行通信,在java中典型的消息传递方式就是wait()和notify()。

9.  线程间如何同步的?

        同步是指程序用于控制不同线程之间操作发生相对顺序的机制。

        在共享内存并发模型里,同步是显式进行的。程序员必须显式指定某个方法或某段代码需要在线程之间互斥执行。

        在消息传递的并发模型里,由于消息的发送必须在消息的接收之前,因此同步是隐式进行的。

10. 谈谈乐观锁与悲观锁?

悲观锁:

        总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。

乐观锁:

        总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。

11. 两种锁的使用场景?

      从上面对两种锁的介绍,我们知道两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下(多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行retry,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。

12. 线程池有什么作用?

        在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程

        第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

        第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。

        第三:提高线程的可管理性。

13. 常用线程池有哪些?:

        ExecutorService 是主要的实现类,其中常用的有        

         1)newCachedThreadPool创建一个可缓存线程池程

         2)newFixedThreadPool 创建一个定长线程池

         3)newScheduledThreadPool 创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行

         4)newSingleThreadExecutor 创建一个单线程化的线程池

14. 线程池的优点?

        1)重用线程池的线程,避免因为线程的创建和销毁锁带来的性能开销

        2)有效控制线程池的最大并发数,避免大量的线程之间因抢占系统资源而阻塞

        3)能够对线程进行简单的管理,并提供一下特定的操作如:可以提供定时、定期、单线程、并发数控制等功能

15. 同步方法和非同步方法可以同时调用?

        可以的

16.  对写方法加锁,对读方法不加锁,可以吗?

        容易产生脏读

17.  一个同步方法可以调用另一个同步方法吗?

        可以,一个线程已拥有某个对象的锁,再次申请的时候仍然会得到该对象的锁,也是说synchronized获得的锁是可重入的。

18. 程序处理中,被锁定方法遇到异常,会怎么样?

        默认情况下锁会被释放,所以并发处理过程中,有异常要多加小心,不然可能会发生不一致的情况。

比如,在一个web app处理过程中,多个servlet线程共同访问同一个资源,这时如果异常处理不合适,在第一个线程中抛出异常,其他线程就会进入同步打码块,有可能访问到异常数据。

19. volatile和synchronized的区别?

        volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。

        volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的

        volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性

        volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。

        volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。

20. synchroized关键字,锁什么地方?

        synchroized锁的是java堆内存中的对某个对象,不是栈中的引用

相关文章

网友评论

    本文标题:java并发面试题总结(1~20题)

    本文链接:https://www.haomeiwen.com/subject/invwoqtx.html