Fork me on GitHub

常用集合

集合

Java 集合框架提供了一套性能优良,使用方便的接口和类,java集合框架位于java.util包中,现分为Collection、Map、Queue三大类。

常用Collection

ArrayList

简介

在多线程环境下,由于线程不安全,会出现各种异常,用于单线程。

代码

public void listDemo(){
        for (int i = 0; i < 30; i++) {
            new Thread(()->{
                while (list.size()>0){
                    System.out.println("卖出: "+list.remove(0)+" 的票");
                }
            }).start();
        }
    }

Vector

简介

在多线程环境下,由于自带synchronized属性,故是线程安全的,不会发生任何异常。

代码

public void vectorDemo(){
        for (int i = 0; i < 30; i++) {
            new Thread(()->{
                while (tickets.size()>0){
                    //这不加锁的原因,①:remove方法是线程安全的 ②:在真正remove之前,会在remove方法里面再次判断size长度
                    System.out.println("卖出: "+tickets.remove(0)+" 的票");
                }
            }).start();
        }
    }

常用Collection

HashMap

简介

HashMap在多线程下,是不安全的,但是运用Collections.synchronizedMap后,线程是安全的,效率和HashTable一样,较差。

代码

public static class Constants {
        public static final int COUNT = 10000;
        public static final int THREAD_COUNT = 10;

    }

    static HashMap<UUID, UUID> m = new HashMap<>();

    static Map<UUID, UUID> mSyn = Collections.synchronizedMap(new HashMap<UUID, UUID>());

    static ConcurrentHashMap<UUID, UUID> mCurr = new ConcurrentHashMap();

    static int count = Constants.COUNT;
    static UUID[] keys = new UUID[count];
    static UUID[] values = new UUID[count];
    static final int THREAD_COUNT = Constants.THREAD_COUNT;

    static {
        for (int i = 0; i < count; i++) {
            keys[i] = UUID.randomUUID();
            values[i] = UUID.randomUUID();
        }
    }

    static class MyThread extends Thread {
        int start;
        int gap = count/THREAD_COUNT;

        public MyThread(int start) {
            this.start = start;
        }

        @Override
        public void run() {
            for(int i=start; i<start+gap; i++) {
                mSyn.put(keys[i], values[i]);
            }
        }
    }

    static class MyThreadCurr extends Thread {
        int start;
        int gap = count/THREAD_COUNT;

        public MyThreadCurr(int start) {
            this.start = start;
        }

        @Override
        public void run() {
            for(int i=start; i<start+gap; i++) {
                mCurr.put(keys[i], values[i]);
            }
        }
    }

public  void hashMapDemo() {

        long start = System.currentTimeMillis();

        Thread[] threads = new Thread[THREAD_COUNT];

        for(int i=0; i<threads.length; i++) {
            threads[i] =new MyThread(i * (count/THREAD_COUNT));
        }

        for(Thread t : threads) {
            t.start();
        }

        for(Thread t : threads) {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        long end = System.currentTimeMillis();
        // HashMap 2    添加Collections.synchronizedMap后 4
        System.out.println(end - start);
        // HashMap 6281   添加Collections.synchronizedMap后 10000
        System.out.println(mSyn.size());
    }

ConcurrentHashMap

简介

多线程时一般使用,插入数据时比HashTable慢,但是读时比HashTable快.

代码

public void  concurrentHashMapDemo(){
        long start = System.currentTimeMillis();
        Thread[] threads = new Thread[THREAD_COUNT];
        for(int i=0; i<threads.length; i++) {
            threads[i] =new MyThreadCurr(i * (count/THREAD_COUNT));
        }
        for(Thread t : threads) {
            t.start();
        }
        for(Thread t : threads) {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        long end = System.currentTimeMillis();
        // 3
        System.out.println(end - start);
        // 10000
        System.out.println(mCurr.size());
    }

ConcurrentSkipListMap

简介

线程安全: 并且自动排序.

代码

public  void ConcurrentSkipDemo() {
        //高并发并且排序
        ConcurrentSkipListMap<String, String> skipMap = new ConcurrentSkipListMap<>();
        Random r = new Random();
        Thread[] ths = new Thread[10];
        CountDownLatch latch = new CountDownLatch(ths.length);
        long start = System.currentTimeMillis();
        for(int i=0; i<ths.length; i++) {
            ths[i] = new Thread(()->{
                for(int j=0; j<10000; j++) {
                    skipMap.put("a"+Thread.currentThread().getName() + j, "a" + r.nextInt(100000));
                };
                latch.countDown();
            });
        }


        Arrays.asList(ths).forEach(t->t.start());
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        long end = System.currentTimeMillis();
        System.out.println(end - start);
        System.out.println(skipMap.size());

    }

常用Queue

Queue队列常用案例: 线程池中。

ConcurrentLinkedDeque

简介

ConcurrentLinkedDeque 是最新的一个接口,主要就是为了多线程使用。方法里面并没有并没有加锁,效率较高。

代码

public void currQueueDemo() {
   ConcurrentLinkedDeque<String> tickets = new ConcurrentLinkedDeque<>();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                while (true) {
                    String s = tickets.poll();
                    if (s == null) {
                        break;
                    } else {
                        System.out.println("销售了--" + s);
                    }
                }
            }).start();
        }
    }

LinkedBlockingQueue

简介

LinkedBlockingQueue则和LinkedList一样,内部基于链表来存放元素,线程安全。

代码

 public void blockQueueDemo() {
        //容器默认最大值为Integer.MAX_VALUE
        LinkedBlockingQueue<String> strs = new LinkedBlockingQueue();

        Random r = new Random();
        new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                try {
                    strs.put("a" + i); //如果满了,就会等待
                    TimeUnit.MILLISECONDS.sleep(r.nextInt(1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "p1").start();

        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                for (; ; ) {
                    try {
                        //如果空了,就会等待
                        System.out.println(Thread.currentThread().getName() + " take -" + strs.take());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "c" + i).start();

        }
    }

ArrayBlockingQueue

简介

使用数组实现的队列,即使用数组实现的“先进先出”的队列,线程安全。

代码

public void arrayBlockingQueueDemo() throws InterruptedException {
        BlockingQueue<String> strs = new ArrayBlockingQueue<>(10);
        for (int i = 0; i < 10; i++) {
            strs.put("a" + i);
        }
        //满了就会等待,程序阻塞
//        strs.put("aaa");
        //满了之后他会报异常
//        strs.add("aaa");
        //offer用返回值来判断到底加没加成功
        strs.offer("aaa");
        //1秒钟之后如果加不进去它就返回到底加没加成功
        strs.offer("aaa", 1, TimeUnit.SECONDS);

        System.out.println(strs);
    }

DelayQueue

简介

DelayQueue可以实现一个优先级排序的队列,具体实现方式为compareTo.

代码

public void delayQueueDemo() throws InterruptedException {
        DelayQueue<MyTask> tasks = new DelayQueue<MyTask>();
        long now = System.currentTimeMillis();
        MyTask t1 = new MyTask("t1", now + 100000);
        MyTask t2 = new MyTask("t2", now + 2000);
        MyTask t3 = new MyTask("t3", now + 1500);
        MyTask t4 = new MyTask("t4", now + 2500);
        MyTask t5 = new MyTask("t5", now + 500);

        tasks.put(t1);
        tasks.put(t2);
        tasks.put(t3);
        tasks.put(t4);
        tasks.put(t5);
        System.out.println(tasks);
        for (int i = 0; i < 5; i++) {
            //take()是阻塞的,一定要等getDelay()方法返回0时,才能取出其数据
            System.out.println(tasks.take());
        }
    }

    public static class MyTask implements Delayed {
        String name;
        long time;

        public MyTask(String name, long time) {
            this.name = name;
            this.time = time;
        }

        /**
         * 元素进入队列后,先进行排序,然后,只有getDelay也就是剩余时间为0的时候,
         * 该元素才有资格被消费者从队列中取出来,所以构造函数一般都有一个时间传入。
         **/
        @Override
        public long getDelay(TimeUnit unit) {
            return unit.convert(time - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
        }

        /**
         * compareTo 方法必须提供与 getDelay 方法一致的排序,也就是说compareTo方法里可以按照
         * getDelay方法的返回值大小排序,即在compareTo方法里比较getDelay方法返回值大小
         **/
        @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;
            }
        }

        @Override
        public String toString() {
            return name + " " + time;
        }
    }

SynchronousQueue

简介

SynchronousQueue容量为0,就是这个东西它不是用来装内容的.

代码

public void synchronusQueueDemo() throws InterruptedException {
        BlockingQueue<String> strs = new SynchronousQueue<>();

        new Thread(()->{
            try {
                System.out.println(strs.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        TimeUnit.MILLISECONDS.sleep(100);
         //阻塞等待消费者消费,没有消费者进行阻塞
//        strs.put("aaa");
        //没有消费者等待,你则不能往其容器中添加元素
        strs.add("aaa");
        System.out.println(strs.size());
    }

LinkedTransferQueue

简介

它可以给线程来传递任务,以此同时不像是SynchronousQueue只能传递一个,TransferQueue做成列表可以传好多个。

代码

public void LinkedTransferQueueDemo() throws InterruptedException {
        LinkedTransferQueue<String> strs = new LinkedTransferQueue<>();

        new Thread(() -> {
            try {
                for (int i = 0; i < 100; i++) {
                    System.out.println(strs.take());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        //装完在这等着,阻塞等有人把它取走我这个线程才回去干我自己的事情。
//        strs.transfer("aaa");

        for (int i = 0; i < 100; i++) {
            strs.put("aaa"+i);
        }
    }

Gitee地址

https://gitee.com/zhuayng/foundation-study/tree/develop/JavaBasis/JUC/src/main/java/com/yxkj/juc/c_002

posted @ 2020-04-25 17:32  晨度  阅读(5288)  评论(0编辑  收藏  举报