前言:Java语言一个重要的特色就是内置了对并发的支持,让Java大受企业和程序员的欢迎。同时,若是想要提高本身的技术,Java并发知识必不可少,这里简单整理了一些相关内容,但愿能够起到抛砖引玉的做用。程序员
1,Java内存模型是什么?算法
Java内存模型规定和指引Java程序在不一样的内存架构、CPU和操做系统间有肯定性地行为。它在多线程的状况下尤为重要。Java内存模型对一个线程所作的变更能被其它线程可见提供了保证,它们之间是先行发生关系。这个关系定义了一些规则让程序员在并发编程时思路更清晰。好比,先行发生关系确保了:编程
线程内的代码可以按前后顺序执行,这被称为程序次序规则。缓存
对于同一个锁,一个解锁操做必定要发生在时间上后发生的另外一个锁定操做以前,也叫作管程锁定规则。安全
前一个对volatile的写操做在后一个volatile的读操做以前,也叫volatile变量规则。数据结构
一个线程内的任何操做必需在这个线程的start()调用以后,也叫做线程启动规则。多线程
一个线程的全部操做都会在线程终止以前,线程终止规则。架构
一个对象的终结操做必需在这个对象构造完成以后,也叫对象终结规则。并发
可传递性框架
2,Java中interrupted 和isInterruptedd方法的区别?
interrupted() 和 isInterrupted()的主要区别是前者会将中断状态清除然后者不会。Java多线程的中断机制是用内部标识来实现的,调用Thread.interrupt()来中断一个线程就会设置中断标识为true。当中断线程调用静态方法Thread.interrupted()来检查中断状态时,中断状态会被清零。
非静态方法isInterrupted()用来查询其它线程的中断状态且不会改变中断状态标识。简单的说就是任何抛出InterruptedException异常的方法都会将中断状态清零。不管如何,一个线程的中断状态都有可能被其它线程调用中断来改变。
3,Java中的同步集合与并发集合有什么区别?
同步集合与并发集合都为多线程和并发提供了合适的线程安全的集合,不过并发集合的可扩展性更高。在Java1.5以前程序员们只有同步集合来用且在多线程并发的时候会致使争用,阻碍了系统的扩展性。Java5介绍了并发集合像ConcurrentHashMap,不只提供线程安全还用锁分离和内部分区等现代技术提升了可扩展性。
无论是同步集合仍是并发集合他们都支持线程安全,他们之间主要的区别体如今性能和可扩展性,还有他们如何实现的线程安全上。
同步HashMap, Hashtable, HashSet, Vector, ArrayList 相比他们并发的实现(ConcurrentHashMap, CopyOnWriteArrayList, CopyOnWriteHashSet)会慢得多。形成如此慢的主要缘由是锁, 同步集合会把整个Map或List锁起来,而并发集合不会。并发集合实现线程安全是经过使用先进的和成熟的技术像锁剥离。
好比ConcurrentHashMap 会把整个Map 划分红几个片断,只对相关的几个片断上锁,同时容许多线程访问其余未上锁的片断。
一样的,CopyOnWriteArrayList 容许多个线程以非同步的方式读,当有线程写的时候它会将整个List复制一个副本给它。
若是在读多写少这种对并发集合有利的条件下使用并发集合,这会比使用同步集合更具备可伸缩性。
4,什么是线程池? 为何要使用它?
建立线程要花费昂贵的资源和时间,若是任务来了才建立线程那么响应时间会变长,并且一个进程能建立的线程数有限。为了不这些问题,在程序启动的时候就建立若干线程来响应处理,它们被称为线程池,里面的线程叫工做线程。从JDK1.5开始,Java API提供了Executor框架让你能够建立不一样的线程池。好比单线程池,每次处理一个任务;数目固定的线程池或者是缓存线程池(一个适合不少生存期短的任务的程序的可扩展线程池)
线程池的做用,就是在调用线程的时候初始化必定数量的线程,有线程过来的时候,先检测初始化的线程还有空的没有,没有就再看当前运行中的线程数是否是已经达到了最大数,若是没有,就新分配一个线程去处理。
就像餐馆中吃饭同样,从里面叫一个服务员出来;但若是已经达到了最大数,就至关于服务员已经用尽了,那没得办法,另外的线程就只有等了,直到有新的“服务员”为止。
线程池的优势就是能够管理线程,有一个高度中枢,这样程序才不会乱,保证系统不会由于大量的并发而由于资源不足挂掉。
5,Java中活锁和死锁有什么区别?
活锁:一个线程一般会有会响应其余线程的活动。若是其余线程也会响应另外一个线程的活动,那么就有可能发生活锁。同死锁同样,发生活锁的线程没法继续执行。然而线程并无阻塞——他们在忙于响应对方没法恢复工做。这就至关于两个在走廊相遇的人:甲向他本身的左边靠想让乙过去,而乙向他的右边靠想让甲过去。可见他们阻塞了对方。甲向他的右边靠,而乙向他的左边靠,他们仍是阻塞了对方。
死锁:两个或更多线程阻塞着等待其它处于死锁状态的线程所持有的锁。死锁一般发生在多个线程同时但以不一样的顺序请求同一组锁的时候,死锁会让你的程序挂起没法完成任务。
6,如何避免死锁?
死锁的发生必须知足如下四个条件:
互斥条件:一个资源每次只能被一个进程使用。
请求与保持条件:一个进程因请求资源而阻塞时,对已得到的资源保持不放。
不剥夺条件:进程已得到的资源,在末使用完以前,不能强行剥夺。
循环等待条件:若干进程之间造成一种头尾相接的循环等待资源关系。
三种用于避免死锁的技术:
加锁顺序(线程按照必定的顺序加锁)
加锁时限(线程尝试获取锁的时候加上必定的时限,超过期限则放弃对该锁的请求,并释放本身占有的锁)
死锁检测
(死锁缘由及如何避免更深理解移步:http://blog.csdn.net/ls5718/article/details/51896159)
7,notify()和notifyAll()有什么区别?
1,notify()和notifyAll()都是Object对象用于通知处在等待该对象的线程的方法。
2,void notify(): 唤醒一个正在等待该对象的线程。
3,void notifyAll(): 唤醒全部正在等待该对象的线程。
二者的最大区别在于:
notifyAll使全部原来在该对象上等待被notify的线程通通退出wait的状态,变成等待该对象上的锁,一旦该对象被解锁,他们就会去竞争。
notify他只是选择一个wait状态线程进行通知,并使它得到该对象上的锁,但不惊动其余一样在等待被该对象notify的线程们,当第一个线程运行完毕之后释放对象上的锁,此时若是该对象没有再次使用notify语句,即使该对象已经空闲,其余wait状态等待的线程因为没有获得该对象的通知,继续处在wait状态,直到这个对象发出一个notify或notifyAll,它们等待的是被notify或notifyAll,而不是锁。
8,什么是可重入锁(ReentrantLock)?
Java.util.concurrent.lock 中的 Lock 框架是锁定的一个抽象,它容许把锁定的实现做为Java 类,而不是做为语言的特性来实现。这就为Lock 的多种实现留下了空间,各类实现可能有不一样的调度算法、性能特性或者锁定语义。 ReentrantLock 类实现了Lock ,它拥有与synchronized 相同的并发性和内存语义,可是添加了相似锁投票、定时锁等候和可中断锁等候的一些特性。此外,它还提供了在激烈争用状况下更佳的性能。(换句话说,当许多线程都想访问共享资源时,JVM能够花更少的时候来调度线程,把更多时间用在执行线程上。)
Reentrant 锁意味着什么呢?简单来讲,它有一个与锁相关的获取计数器,若是拥有锁的某个线程再次获得锁,那么获取计数器就加1,而后锁须要被释放两次才能得到真正释放。这模仿了synchronized 的语义;若是线程进入由线程已经拥有的监控器保护的synchronized 块,就容许线程继续进行,当线程退出第二个(或者后续)synchronized块的时候,不释放锁,只有线程退出它进入的监控器保护的第一个synchronized 块时,才释放锁。
9,读写锁能够用于什么应用场景?
读写锁能够用于 “多读少写” 的场景,读写锁支持多个读操做并发执行,写操做只能由一个线程来操做
ReadWriteLock对向数据结构相对不频繁地写入,可是有多个任务要常常读取这个数据结构的这类状况进行了优化。ReadWriteLock使得你能够同时有多个读取者,只要它们都不试图写入便可。若是写锁已经被其余任务持有,那么任何读取者都不能访问,直至这个写锁被释放为止。
ReadWriteLock 对程序性能的提升主要受制于以下几个因素:
1,数据被读取的频率与被修改的频率相比较的结果。
2,读取和写入的时间
3,有多少线程竞争
4,是否在多处理机器上运行
5,Java高并发锁的3种实现 http://www.roncoo.com/article/detail/128506