文章目录
1.JUC核心类的深度解析与使用案例
1.1使用CopyOnWriteLock实现并发写操作
原理:遇到写操作时,CopyOnWrite先将当前容器复制一份,然后向新的容器(复制后的容器)添加新的元素(不会直接在当前容器中添加元素);添加完后,再将引用指向新的容器,原容器等待GC回收。
所以CopyOnWrite更加适合“读多写少”的场景。
1.2使用ReadWriteLock实现读写锁
- readLock():加了读锁的资源,在没有写锁的时候可以被多个线程共享。
- writeLock():写锁,独占锁。加了写锁的资源, 不能再被其它线程读或者写。
1.3ConcurrentHashMap的底层结构
- java7中,hashmap使用数组+链表的方式实现。ConcurrentHashMap是对segment加锁,每一个元素是一个segment,加大了锁的粒度,保证了线程安全。
- java8中,hashmap使用数组+红黑树的方式实现。ConcurrentHashMap则放弃了对segment加锁,转而使用volatile,严重时使用synchronized和CAS算法来保证线程安全。
1.4使用BlockingQueue实现排序和定时任务
BlockingQueue可以对队列中的元素排序,以及实现定时任务等功能。
1.5通过CountDownLatch实现多线程闭锁
CountDownLatch是一个同步工具类,可以用来协调多个线程的执行时间。如可以让a线程在b线程执行完之后执行。a在这时会一直等待b的执行。这个过程也叫“闭锁”(某个线程被堵在门外得一直等待)。
闭锁通常用于确保某个计算,确保某个服务,确保某个任务。
CountDownLatch类似一个倒计时,设置一个数字后,执行一个线程的任务后,调用一次 CountDownLatch ,计数器减一。直到减为0,释放。
1.6使用CyclicBarrier在多线程设置屏障
与 CountDownLatch的区别:
-
CountDownLatch:可以实现a和b全部执行完成后,c再去执行。
-
CyclicBarrier:可以实现a,b等到c就绪后,一起执行。
1.7使用FutureTask和Callable实现多线程
创建多线程,可以继承Thread类,或者实现Runnable接口。JUC还提供了一种实现方式,Callable+FutureTask。
FutureTask是客户端向服务端发起一个请求后,服务端会立即给客户端返回一个结果。但实际任务并没有执行。客户端在拿到假的响应的同时,服务端才会去执行任务,并在任务结束后,将真的执行结果返回给客户端。
这样做的好处是,客户端发起一个请求后,可以立马得到结果,而不用一直去等待服务端的执行结果。
2.通过源码掌握并发包的基石AQS
AQS中维护着一个表示共享资源加锁状态的一个变量volatile int state(标示该资源被加锁次数),以及一个FIFO的线程阻塞队列(CLH队列)
多个线程访问共享资源时,如果资源已经被加了锁,那么所有线程将会加入CLH队列中进行等待。
加锁方式有两种
- 独占锁Exclusive
- 共享锁Share