首页 > 编程语言 > 详细

线程安全的集合

时间:2020-12-11 22:55:28      阅读:34      评论:0      收藏:0      [点我收藏+]

线程安全的集合

  • CopyOnWriteArrayList
    • 线程安全的ArrayList,加强版的读写分离。
    • 写有锁,读无锁,读写之间不阻塞,由于读写锁
    • 写入时,先copy一个容器副本、再添加新元素,最后替换引用。(浪费空间
    • 使用方式与ArrayList无异。
package com.sun.base.XianCheng;

import java.util.List;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 使用多线程操作CopyOnWriteArrayList
 */
public class Mylist {
    public static void main(String[] args) {
        //创建集合
        List<String> list=new CopyOnWriteArrayList<>();
        //创建线程池
        ExecutorService es = Executors.newFixedThreadPool(5);
        //提交任务
        for (int i=0;i<5;i++){
            es.submit(new Runnable() {
                @Override
                public void run() {
                    for (int j =0;j<10;j++){
                        list.add(Thread.currentThread().getName()+"---"+new Random().nextInt(1000));
                    }
                }
            });
        }
        //关闭线程池
        es.shutdown();
        while (!es.isTerminated()){}
        //打印结果
        System.out.println(list.size());
        for (String str:list) {
            System.out.println(str.toString());
        }
    }

}
  • CopyOnWriteArraySet
    • 线程安全的Set,底层使用CopyOnWriteArrayList实现。
    • 唯一不同在于,使用addIfAbsent()添加元素,会遍历数组,如存在元素,则不添加(扔掉副本)。
    • 重复依据:equals方法。
package com.sun.base.XianCheng;
import java.util.concurrent.CopyOnWriteArraySet;
/**
 * 演示CopyOnWriteArraySet
 */
public class MySet {
    public static void main(String[] args) {
        //创建集合
        CopyOnWriteArraySet<String> strings = new CopyOnWriteArraySet<>();
        //添加元素
        strings.add("aaa");
        strings.add("bbb");
        strings.add("ccc");
        strings.add("ddd");
        strings.add("aaa");
        //打印
        System.out.println("元素个数:"+strings.size());
        System.out.println(strings.toString());//有序
    }
}

Queue接口(队列)

  • Collection的子接口,表示队列FIFO(先进先出)

  • 常见方法:

    • 抛出异常:
      • boolean add(E e)//顺序添加一个元素(到达上限后,再添加则会抛出异常)
      • E remove()//获得第一个元素并移除(如果队列没有元素时,则抛出异常)
      • E element()//获得第一个元素但不移除(如果队列没有元素时,则会抛出异常)
    • 返回特殊值:推荐使用
      • boolean offer(E e)//顺序添加一个元素(到达上限后,再添加则会返回false)
      • E poll()//获得第一个元素并移除(如果队列没有元素时,则返回null)
      • E peek()//获得第一个元素但不移除(如果队列没有元素时,则返回null)
  • ConcurrentLinkedQueue

    • 线程安全、可高效读写的队列,高并发下性能最好的队列。
    • 无锁、CAS比较交换算法,修改的方法包含三个核心参数(V,E,N)
    • V:要更新的变量;E:预期值;N:新值。
    • 只有当VE时,VN;否则表示已被更新过,则取消当前操作。
package com.sun.base.XianCheng;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
 * ConcurrentLinkedQueue的使用
 */
public class MyConcurrentLinkedQueue {
    public static void main(String[] args) throws InterruptedException {
        //创建安全队列
        ConcurrentLinkedQueue<Integer> integers = new ConcurrentLinkedQueue<>();
        //创建线程
        Thread thread=new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <= 5; i++) {
                    integers.offer(i);
                }
            }
        });
        Thread thread1=new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 6; i <= 10; i++) {
                    integers.offer(i);
                }
            }
        });
        //启动线程
        thread.start();
        thread1.start();
        thread.join();
        thread1.join();
        //出队
        int size=integers.size();
        for (int i=0;i<size;i++){
            System.out.println(integers.poll());
        }
    }
}
  • BlockingQueue接口(阻塞队列)

    • Queue的子接口,阻塞的队列,增加了两个线程状态为无限期等待的方法。

    • 方法:

      • void put(E,e) //将指定的元素插入次队列中,如果没有可用空间,则等待。
      • E take() //获取并移除次队列头部元素,如果没有可用元素,则等待。
    • 可用于解决生产者、消费者问题。

    • 实现类

      • ArrayBlockingQueue:数组结构实现,有界队列。(手工固定上限)

        package com.sun.base.XianCheng;
        
        import java.util.concurrent.ArrayBlockingQueue;
        
        /**
         * 阻塞队列的使用
         * 案例1:实现生产者和消费者
         */
        public class MyBlockingQueue {
            public static void main(String[] args) throws InterruptedException {
                //创建一个有界队列
                ArrayBlockingQueue<Integer> strings = new ArrayBlockingQueue<>(6);//固定面包上限为6
                //创建两个线程
                Thread t1=new Thread(new Runnable() {
                    @Override
                    public  void  run() {
                        for (int i=1;i<20;i++){
                            try {
                                strings.put(i);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            System.out.println(Thread.currentThread().getName()+"生产了第"+i+"号面包");
                        }
                    }
                },"小明");
                Thread t2=new Thread(new Runnable() {
                    @Override
                    public  void run() {
                        for (int i=1;i<20;i++){
                            try {
                                strings.take();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            System.out.println(Thread.currentThread().getName()+"消费了第"+i+"号面包");
                        }
                    }
                },"小红");
                t1.start();
                t2.start();
            }
        }
        
      • LinkedBlockingQueue:链表结构实现,有界队列。(默认上限Integer.MAX_VALUE)

  • ConcurrentHashMap

    • 初始容量默认为16段(Segment),使用分段锁设计。
    • 不对整个Map加锁,而是为每个Segment加锁。
    • 当多个对象存入同一个Segment时,才需要互斥。
    • 最理想状态为16个对象分别存入16个Segment,并行数量16。
    • 使用方式与HashMap无异。
package com.sun.base.XianCheng;

import java.util.concurrent.ConcurrentHashMap;

/**
 * ConcurrentHashMap的使用
 */
public class MyConcurrentHashMap {
    public static void main(String[] args) {
        //创建集合
        ConcurrentHashMap<String, String> hashMap = new ConcurrentHashMap<>();
        //使用多线程添加数据
        for (int i=0;i<5;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j=0;j<4;j++){
                        hashMap.put(Thread.currentThread().getName()+"---"+j,j+"  ");
                        System.out.println(hashMap);
                    }

                }
            }).start();
        }
    }
}

线程安全的集合

原文:https://www.cnblogs.com/mrhk/p/14122096.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!