volatile能否保证线程安全
1,线程安全要考虑三个方面:可见性、有序性、原子性
①,可见性指,一个线程对共享变量修改,另一个线程能看到最新的结果
②,有序性指,一个线程内多行代码以一个整体运行,期间不能有其它线程的代码插队。
③,原子性,一个线程内多行代码之间以一个整体运行,期间不能有其它线程的代码插队
volatile能够保证共享变量的可见性与有序性,但不能保证原子性。
java中的悲观锁与乐观锁
1,悲观锁的代表是synchronized和Lock锁
①,其核心是【线程只有占有了锁,才能去操作共享变量,每次只能有一个线程占锁成功,获取锁失败的线程,都得停下来等待】
②,线程从运行到阻塞,再从阻塞到唤醒,涉及线程上下文切换,如果频繁发生,影响性能。
③,实际上,线程在获取synchronized和Lock锁时,如果锁已被占用,都会做几次重试操作,减少阻塞机会。
2,乐观锁的代表是Atomiclnteger,使用cas来保证原子性(AtomicInteger底层是unsafe)
①,其核心思想是【无需加锁,每次只有一个线程能成功修改共享变量,其它失败的线程不需要停止,不断重试直至成功】
②,由于线程一直运行,不需要阻塞,因此不涉及线程上下文切换
③,它需要多核cpu支持,且线程数不应超过cpu核数。
注:cas要和volatile一起使用
Hashtable 和 ConcurrentHashMap
相同点:Hashtable与ConcurrentHashMap都是线程安全的Map集合
不同点:
1,Hashtable并发度低,整个Hashtable对应一把锁,同一时刻,只能有一个线程操作它。其它线程都得排到锁的阻塞队列中
2, 1.8之前ConcurrentHashMap将数组的每个头结点作为锁,如果多个线程访问的头结点不同,则不会冲突(同一时刻,有多少个线程能够访问你)
3, 1.8开始ConcurrentHashMap将数组的每个头结点作为锁,如果多个线程访问的头节点不同,则不会冲突。
对ThreadLocal的理解
1,ThreadLocal可以实现【资源对象】的线程隔离,让每个线程各用各的【资源对象】,避免争用引发的线程安全问题。
2,ThreadLocal同时实现了线程内资源共享
3,其原理是,每个线程内有一个ThreadLocalMap类型的成员变量,用来存储资源对象
①,调用set方法,就是以ThreadLocal自己作为key,资源对象作为value,放入当前线程的ThreadLocalMap集合中
②,调用get方法,就是以ThreadLocal自己作为key,到当前线程中查找关联的资源值。
③,调用remove方法,就是以ThreadLocal自己作为key,移除当前线程关联的资源值。
为什么ThreadLocalMap中的key(即ThreadLocal)要设计为弱引用?
①,Thread可能需要长时间运行(如线程池中的线程),如果key不再使用,需要在内存不足(GC)时释放其占用的内存
②,但GC仅是让key的内存释放,后续还要根据key是否为null来进一步释放值的内存,释放时机有
· a,获取key发现null key
· b,set key时,会使用启发式扫描,清除临近的null key,启发次数与元素个数,是否发现null key有关
· c,remove时,因为一般使用ThreadLocal时都把它作为静态变量,因此GC无法回收。
高并发中的集合有哪些问题?
Java的集合类,前前后后经历了三代演进过程。
第一代线程安全集合类
Vector、Hashtable
是怎么保证线程安全的:使用synchronized修饰方法
缺点:效率低下
第二代线程非安全集合类
ArrayList、HashMap
线程不安全,但是性能好,用来替代Vector、Hashtable
使用ArrayList、HashMap,需要线程安全怎么办?
使用Collections.synchronizedList(list); Collections.synchronizedMap(m);
第三代线程安全集合类
在大量并发情况下如何提高集合的效率和安全呢?
java.util.Concurrent.*
ConcurrentHashMap;
CopyOnWriteArrayList;
CopyOnWriteArraySet:注意不是CopyOnWriteHashSet*
底层大都采用Lock锁,保证安全的同时,性能也很高。