关于同步类容器和并发类容器,高性能ConcurrentLinkedQueue,阻塞式BlockingQueue接口的一些实现,例如ArrayBlockQueue,LinkedBlockingQueue,SynchronousQueue,PriorityBlockingQueue,DelayQueue的实现及一些应用场景
1.关于同步类容器和并发类容器
- package com.wpx.thread.demo04;
- import java.util.Map;
- import java.util.concurrent.ConcurrentHashMap;
- import java.util.concurrent.CopyOnWriteArrayList;
- import java.util.concurrent.CopyOnWriteArraySet;
- /**
- * 同步类容器:如Vector,Has和Table这些容器的同步功能其实都是JDK的Collections,synchronized等工厂方法创建实现
- *
- * 同步类容器都是线程安全的,但某些场景下需要加锁俩保护复合操作
- * 如:迭代(反复访问元素,遍历完容器中的所有元素)
- * 跳转(根据当前元素按照特定顺序去查找下一个元素)
- *
- * 因为同步类容器通过大量使用synchronized关键字,通过锁的方式使得只有一个线程可以操作数据
- * 同步类容器都是串行化的,他们虽然实现了线程安全,但是严重降低了并发性,在多线程环境下,严重降低了应用程序的吞吐量
- * 为解决这些问题jdk提供了多种并发类容器来替代同步类容器从而改善性能
- *
- * 使用ConcurrentHashMap 来代替给予散列的传统的HashTable
- * 以及使用CopyOnWriterArrayList代替Voctor
- * 并发的CopyonWriterAr raySet
- * 以及并发的Queue,高性能的队列ConcurrentLinkedQueue,阻塞式的队列LinkedBlockingQueue
- * 具体实现Queue还有ArrayBlockQueue,PriorityBlockingQueue,SynchronizedQueue等
- *
- *
- * ConcurrentMap接口有两个重要的实现
- * ConcurrentHashMap
- * ConcurrentSkipListMap (支持并发排序功能,弥补ConcurrentMapHashMap)
- *
- * ConcurrentHashMap内部使用断来表示这些不同的部分,每个段其实就是一个小的HashTale他们有自己的锁
- * 只要多个修改操作发生在不同的段上,他们就可以并发的记性,把一个整体分成了16个段,也就是最高支持16个线程的并发修改操作
- * 这也是在多线程场景时减少锁粒度从而降低锁竞争的一种方案,将大多共享变量使用volatile关键字声明,进而实时的获得修改的内容
- *
- * 对于CopyOnWriter容器便是一个即写时复制
- * 在对容器元素进行修改时,不直接在当前容器修改,而是将当前容器进行复制,在新的容器中进行修改,在修改完成后,将原容器的引用执向新的容器
- * 好处是我们可以对CopyOnWriter容器进行并发的读,而不需要加锁,即COW是一种读写分离的容器
- * 应用场景:读多写少
- *
- *
- * @author wangpx
- */
- public class demo01 {
- public static void main(String[] args) {
- ConcurrentHashMap<String,Object> map=new ConcurrentHashMap<String,Object>();
- map.put("k1", "k1value");
- map.putIfAbsent("k1", "k1值");
- for (Map.Entry<String, Object> m : map.entrySet()) {
- System.out.println("Key:" +m.getKey()+" : "+m.getValue());
- }
- CopyOnWriteArraySet<String> s=new CopyOnWriteArraySet<String>();
- CopyOnWriteArrayList<String> list=new CopyOnWriteArrayList<>();
- }
- }
- package com.wpx.thread.demo04;
- import java.util.concurrent.ConcurrentLinkedQueue;
- /**
- * ConcurrentLinkedQueue:
- * 适用于高并发场景下的队列,通过无锁的方式,实现了高并发状态下的高性能,通常情况下ConcurrentQuueu性能好于BlockingQueue
- * 他是一个基于链接节点的无界线程安全队列,该队列的元素遵循先进先出的原则,该队列不允许null元素
- *
- * ConcurrentLinkedQueue的重要方法
- * add()和offer()都是加入元素的方法,zaiConcurrentLinkedQueue中这两个方法没有区别
- * poll()和peek()都是取头元素节点,区别在于前者会删除元素,后者不会
- *
- * @author wangpx
- */
- public class demo02 {
- public static void main(String[] args) {
- ConcurrentLinkedQueue<String> queue=new ConcurrentLinkedQueue<String>();
- queue.add("1");
- queue.add("2");
- System.out.println(queue.poll());;
- System.out.println(queue.size());
- System.out.println(queue.peek());
- System.out.println(queue.size());
- }
- }
- package com.wpx.thread.demo04;
- import java.util.concurrent.ArrayBlockingQueue;
- import java.util.concurrent.TimeUnit;
- /**
- *
- * BlockingQueue接口
- *
- * ArrayBlockQueue:基于数组的阻塞队列实现,在ArrayBlockQueue内部,维护了一个定长的数组,
- * 便于缓存队列中的数据对象,,其内部没有实现读写分离,也就意味着生产和消费不能完全并行,长度需要定义,
- * 可以指定先进先出或者先进后出,也叫有界队列
- *
- * @author wangpx
- */
- public class demo03 {
- public static void main(String[] args) throws Exception{
- /**
- * false
- * Exception in thread "main" java.lang.IllegalStateException: Queue full
- at java.util.AbstractQueue.add(AbstractQueue.java:98)
- at java.util.concurrent.ArrayBlockingQueue.add(ArrayBlockingQueue.java:312)
- at com.wpx.thread.demo04.demo03.main(demo03.java:41)
- *
- */
- ArrayBlockingQueue<String> array=new ArrayBlockingQueue<String>(3);
- array.add("a");
- array.add("b");
- array.add("c");
- System.out.println(array.offer("c", 1, TimeUnit.SECONDS));
- array.add("d");
- }
- }
4.LinkedBlockingQueue
- package com.wpx.thread.demo04;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.concurrent.LinkedBlockingQueue;
- import java.util.concurrent.TimeUnit;
- /**
- * LinkedBlockingQueue:基于链表的阻塞队列,,同ArrayBlockingQueue类似,其内部也维持着一个数据缓冲队列
- * 队列由数据缓冲队列,队列由一个链表构成,LinkedBlockingQueue之所以能高效的处理并发数据是因为其内部采用分离锁
- * 从而实现生产者和消费者的完全并行处理,他是一个无界队列
- * @author wangpx
- */
- public class demo04 {
- /**
- * true
- drainTo方法 批量去数据
- ab
- * @param args
- * @throws Exception
- */
- public static void main(String[] args) throws Exception{
- LinkedBlockingQueue<String> queue =new LinkedBlockingQueue<String>();
- queue.add("a");
- queue.add("b");
- queue.add("c");
- System.out.println(queue.offer("d", 1, TimeUnit.SECONDS));
- queue.add("e");
- List<String> list=new ArrayList<>();
- queue.drainTo(list, 2);
- list.stream().forEach(System.out::print);
- }
- }
- package com.wpx.thread.demo04;
- import java.util.concurrent.SynchronousQueue;
- /**
- * SynchronousQueue:一种没有缓冲的队列,生产者生产的数据直接会被消费者获取并消费
- * 这个队列没有容量
- * @author wangpx
- */
- public class demo05 {
- public static void main(String[] args) {
- SynchronousQueue<String> queue=new SynchronousQueue<>();
- /**
- * Exception in thread "main" java.lang.IllegalStateException: Queue full
- at java.util.AbstractQueue.add(AbstractQueue.java:98)
- at com.wpx.thread.demo04.demo05.main(demo05.java:13)
- */
- queue.add("a");
- }
- }
6.DelayQueue
- package com.wpx.thread.demo04;
- import java.util.concurrent.DelayQueue;
- import java.util.concurrent.Delayed;
- import java.util.concurrent.TimeUnit;
- /**
- *
- DelayQueue带有延迟时间的Queue,其中的元素只有当指定的延迟时间到了,才能够从队列中获取到该元素
- DelayQueue中的元素必须实现Dalayed接口
- DelayQueue没有大小限制
- DelayQueue应用场景: 对缓存超时的数据移除,任务超时处理,空闲连接的关闭
- 网吧开始营业
- 网名为:w身份证为:1996交钱1块,开始上级
- 网名为:p身份证为:1995交钱5块,开始上级
- 网名为:x身份证为:1994交钱3块,开始上级
- 网名为:w身份证为:1996下机了
- 网名为:x身份证为:1994下机了
- 网名为:p身份证为:1995下机了
- * @author wangpx
- */
- public class WangBa implements Runnable{
- private DelayQueue<WangMin> queue=new DelayQueue<WangMin>();
- public boolean yingye=true;
- public void shangji(String name,Integer id,int money) {
- WangMin wangmin=new WangMin(id, name, 1000*money+System.currentTimeMillis());
- System.out.println("网名为:"+wangmin.getName()+"身份证为:"+wangmin.getId()+"交钱"+money+"块,开始上级");
- this.queue.add(wangmin);
- }
- public void xiaji(WangMin wangmin) {
- System.out.println("网名为:"+wangmin.getName()+"身份证为:"+wangmin.getId()+"下机了");
- }
- @Override
- public void run() {
- while(yingye) {
- try {
- WangMin w=queue.take();
- xiaji(w);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- public static void main(String[] args) {
- try {
- System.out.println("网吧开始营业");
- WangBa w=new WangBa();
- Thread shangnwang=new Thread(w);
- shangnwang.start();
- w.shangji("w", 1996, 1);
- w.shangji("p", 1995, 5);
- w.shangji("x", 1994, 3);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- class WangMin implements Delayed{
- private Integer id;
- private String name;
- private long endTime;
- private TimeUnit timeUnit=TimeUnit.SECONDS;
- public WangMin() {
- }
- public WangMin(Integer id, String name, long endTime) {
- super();
- this.id = id;
- this.name = name;
- this.endTime = endTime;
- }
- public Integer getId() {
- return id;
- }
- public String getName() {
- return name;
- }
- @Override
- public int compareTo(Delayed delayed) {
- WangMin wangMin=(WangMin) delayed;
- return this.getDelay(this.timeUnit) -wangMin.getDelay(this.timeUnit)> 0 ? 1: 0;
- }
- @Override
- public long getDelay(TimeUnit unit) {
- return endTime - System.currentTimeMillis();
- }
- }
- package com.wpx.thread.demo04;
- import java.util.concurrent.PriorityBlockingQueue;
- /**
- * PriorityBlockingQueue:基于优先级的阻塞队列,优先级的判断通过函数传入的Compator对象来决定,
- * 也就是说传入队列的对象必须实现Comparable接口
- * 在实现PriorityBlockingQueue时,内部控制线程同步的锁采用的是公平锁,他是一个无界的队列
- * @author wangpx
- */
- public class demo07 {
- /**
- wapx1
- wpx5
- wpx15
- wpx8
- wpx27
- ------------------
- wapx1
- wpx5
- wpx8
- wpx15
- wpx27
- 底层选出一个优先级最高的,一个take一次比较
- * @param args
- */
- public static void main(String[] args) throws Exception{
- PriorityBlockingQueue<Student> queue=new PriorityBlockingQueue<Student>();
- Student s1=new Student(8, "wpx8");
- Student s2=new Student(1, "wapx1");
- Student s3=new Student(15, "wpx15");
- Student s4=new Student(5, "wpx5");
- Student s5=new Student(27, "wpx27");
- queue.add(s1);
- queue.add(s2);
- queue.add(s3);
- queue.add(s4);
- queue.add(s5);
- queue.stream()
- .map((e)-> e.getName())
- .forEach(System.out::println);
- System.out.println("------------------");
- int size = queue.size();
- for(int i=0;i<size;i++) {
- System.out.println(queue.take().getName());
- }
- }
- }
- class Student implements Comparable<Student>{
- private Integer id;
- private String name;
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Student() {
- }
- public Student(Integer id, String name) {
- this.id = id;
- this.name = name;
- }
- @Override
- public int compareTo(Student student) {
- return this.id>student.id ? 1: (this.id<student.id ? -1 :0);
- }
- }