多线程高并发编程学习笔记三

高并发编程学习笔记三:并发容器/队列
1. map/set的选择使用
    1. 不需要线程安全
        hashmap:无序的key- value 1.创建table来存储entry 2.hashcode(key)得到键值对应该存放的位置 3.用equal方法比较key,如果相同覆盖数据,如果不同接到下面形成链表
        treemap:有顺序的红黑树实现的map
        Linkedhashmap:HashMap和双向链表合二为一即是LinkedHashMap,它是一个将所有Entry节点链入一个双向链表双向链表的HashMap。每个entry增加了两个参数before与next来标注前后两个entry是谁,从而实现了有序的hashmap
    2. 需要线程安全(并发并不高的情况)
        HashTable:线程安全的hashmap,方法上都加了synchronized
        Collections.SynchronizedXXX:传入不加锁的map/list,返回给一个包装好的加锁线程安全的map/list。
    3.需要线程安全(并发并不高的情况)
        concurrentHashMap:无序,分段锁不像hashtable那样把整个hashmap都锁定起来。分段锁定,需要哪一段就锁定哪一段,所以效率更高。
        concurrentSkiplistmap:默认以key值升序排列的map,有序。
2.CopyOnWriteList:写的效率非常低,读的效率非常高
    1.为什么写的效率非常低:每次写入数据,先把list复制然后将需要写入的数据放到list的末尾,然后将引用重新制定到新的list上面
    2.为什么读的效率高:因为读的方法不需要加锁了
3.ConcurrentLinkedqueue/ConcurrentLinkeddeque:单向链表队列与双向链表队列(并发队列)
    1. offer():相当于add方法添加一个对象到队列中
    2. poll():getAndRemoveFirst方法
    3. peek():get方法,并不会从队列中remove    
    4. 双向链表队列与之类似,只是可以双向操作
4. BlockingQueue阻塞式队列:如果满了等待,如果空了等待
    1.LinkedBQ:链表实现的阻塞式队列,无边界
    2.ArrayBQ:数组实现的阻塞式队列,有边界
    

public class LinkedBolockingQueue {
    //    static LinkedBlockingQueue<Object> queue = new LinkedBlockingQueue<>();
        static ArrayBlockingQueue<Object> queue = new ArrayBlockingQueue<>(10);

        public static void main(String[] args){
            //生产者线程
            for(int t=0;t<5;t++){
                new Thread(()->{
                    for(int i = 0 ;i<1000 ; i++){
                        try {
                            queue.put(new Object());//满了就会等待,程序阻塞
                            queue.add(new Object());//如果满了的情况,add会提示异常,报错
                            queue.offer(new Object());//如果满了的情况,offer没有异常,因为offer是一个返回值为boolean的函数,通过但会的boolean显示是否添加成功。此时满了没有报错返回值为false
                            System.out.println("put size : "+queue.size());
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
            //消费者线程
            for(int i=0;i<10;i++){
                new Thread(()->{
                    for(int t=0;t<500;t++){
                        try {
                            queue.take();//自动等待
                            System.out.println("take size : "+queue.size());
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        }
    }


5. DelayQueue延迟队列:执行定时任务,在该队列中添加元素的时候需要指定多长时间之后执行该元素,而且添加的元素需要实现delayed接口,实现内部比较器。
    

public class DelayQueue {
        static BlockingQueue<MyTask> myTasks = new java.util.concurrent.DelayQueue<>();

        public static void main(String[] args) throws InterruptedException {
                myTasks.put(new MyTask(System.currentTimeMillis() + 1000));
                myTasks.put(new MyTask(System.currentTimeMillis() + 500));
                myTasks.put(new MyTask(System.currentTimeMillis() + 1500));
                myTasks.put(new MyTask(System.currentTimeMillis() + 2000));
                myTasks.put(new MyTask(System.currentTimeMillis() + 100));
                for (int i=0 ;i<5;i++){
                    System.out.println(myTasks.take().runningTime);//take()获取并移除头部
                }
        }
        static class MyTask implements Delayed{
            Long runningTime;

            public MyTask(long l) {
                this.runningTime = l;
            }
            //设置时间单位
            @Override
            public long getDelay(TimeUnit unit) {
                return unit.convert(runningTime - System.currentTimeMillis(),TimeUnit.MILLISECONDS);
            }
            //内部比较器
            @Override
            public int compareTo(Delayed o) {
                if(this.getDelay(TimeUnit.MILLISECONDS) < o.getDelay(TimeUnit.MILLISECONDS))
                    return -1;
                else if(this.getDelay(TimeUnit.MILLISECONDS) > o.getDelay(TimeUnit.MILLISECONDS))
                    return 1;
                else return 0;
            }
        }
    }


6.TransferQueue:阻塞式队列,TransferQueue是一个继承了BlockingQueue的接口,并且增加若干新的方法。LinkedTransferQueue是TransferQueue接口的实现类,其定义为一个无界的队列,具有先进先出(FIFO)的特性。
    如果有消费者线程在等待,立马把元素移交给消费之线程,如果没有。将元素放入队列末尾,然后生产者线程堵塞,直到有人取走
    LinkedTransferQueue实现了一个重要的接口TransferQueue,该接口含有下面几个重要方法:
     1. transfer(E e):若当前存在一个正在等待获取的消费者线程,即立刻移交之;否则,会插入当前元素e到队列尾部,并且等待进入阻塞状态,到有消费者线程取走该元素。
     2. tryTransfer(E e):若当前存在一个正在等待获取的消费者线程(使用take()或者poll()函数),使用该方法会即刻转移/传输对象元素e;若不存在,则返回false,并且不进入队列。这是一个不阻塞的操作。
     3. tryTransfer(E e, long timeout, TimeUnit unit):若当前存在一个正在等待获取的消费者线程,会立即传输给它;否则将插入元素e到队列尾部,并且等待被消费者线程获取消费掉;若在指定的时间内元素e无法被消费者线程获取,则返回false,同时该元素被移除。
7.SynchronusQueue:同步容器阻塞式队列,特殊的transferQueue,他的容量为0,所有的元素必须马上交给消费者。不能放到容器中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值