java并发容器简述

xiaoxiao2021-02-28  107

Hashtable

往里面添加任何对象的时候,都要锁定整个对象

ConcurrentHashMap 默认把整个容器分成16段每一次往里面插入的时候,只锁定16段中的一段。 ConcurrentHashMap就是把锁给细化了,当很多线程往里面插入数据的时候,就可以并发的插入,只锁定当前这一块,而不需要锁定整个对象。它把大锁变成了小锁。

ConcurrentSkipListMap

支持高并发,并且插入数据的时候需要,排序,则需要调跳表map

详解: http://blog.csdn.net/sunxianghuang/article/details/52221913 public class T01_ConcurrentMap { public static void main(String[] args) { Map<String, String> map = new ConcurrentHashMap<>(); //Map<String, String> map = new ConcurrentSkipListMap<>(); //高并发并且排序 //Map<String, String> map = new Hashtable<>(); //Map<String, String> map = new HashMap<>(); //Collections.synchronizedXXX //TreeMap Random r = new Random(); Thread[] ths = new Thread[100]; 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++) map.put("a" + r.nextInt(100000), "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); } } Collection.synchronizedMap(Map<k,v>m) 传入一个不加锁的map返回给你一个加锁的map,所以你拿到的新的容器就已经是加锁了的。 public class T03_SynchronizedList { public static void main(String[] args) { List<String> strs = new ArrayList<>(); List<String> strsSync = Collections.synchronizedList(strs); } } CopyOnWriteArrayList

写时复制,写的效率非常低,读的效率非常高。 这个容器往里面添加一个新的元素的时候,它会把这个容器复制一份,然后在后面加一个新的

然后把这个引用加到后面。 有点想数据库读写分离,适用于写的很少,读很多的并发环境。 public class T02_CopyOnWriteList { public static void main(String[] args) { List<String> lists = //new ArrayList<>(); //这个会出并发问题! //new Vector(); new CopyOnWriteArrayList<>(); Random r = new Random(); Thread[] ths = new Thread[100]; for(int i=0; i<ths.length; i++) { Runnable task = new Runnable() { @Override public void run() { for(int i=0; i<1000; i++) lists.add("a" + r.nextInt(10000)); } }; ths[i] = new Thread(task); } runAndComputeTime(ths); System.out.println(lists.size()); } static void runAndComputeTime(Thread[] ths) { long s1 = System.currentTimeMillis(); Arrays.asList(ths).forEach(t->t.start()); Arrays.asList(ths).forEach(t->{ try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } }); long s2 = System.currentTimeMillis(); System.out.println(s2 - s1); } }

上面的都是map,可以换成set也是试用的。 说到底map和set底层实现都大同小异

Queue offer:相当于add,但是如果在arraylist中add越界会抛异常 poll:从头上拿一个元素,会删除 peek : 从头上拿一个,不删除 ConcurrentLinkedQueue 无界队列,底层是用链表实现 public class T04_ConcurrentQueue { public static void main(String[] args) { Queue<String> strs = new ConcurrentLinkedQueue<>(); for(int i=0; i<10; i++) { strs.offer("a" + i); //相当于add,但是如果在arraylist中add越界会抛异常 } System.out.println(strs); System.out.println(strs.size()); System.out.println(strs.poll()); //从头上拿一个,删 System.out.println(strs.size()); System.out.println(strs.peek()); //从头上拿一个,不删 System.out.println(strs.size()); } } BlockingQueue 阻塞试队列,实现了这个接口的容器,天然的就可以形成生产者和消费者模式。 put:添加元素,如果满了,就会等待。 take: 拿一个元素,如果容器空了,就会等待 add : 添加一个元素,如果满了就会抛出异常 offer : 添加一个元素,如果满了不会报异常,当然可不会添加成功,会返回一个boolean类型告诉你是不是添加成功。 LinkedBlockingQueue

无界队列,底层链表实现。

public class T05_LinkedBlockingQueue { static BlockingQueue<String> strs = new LinkedBlockingQueue<>(); static Random r = new Random(); public static void main(String[] args) { 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 class T06_ArrayBlockingQueue { static BlockingQueue<String> strs = new ArrayBlockingQueue<>(10); static Random r = new Random(); public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 10; i++) { strs.put("a" + i); } strs.put("aaa"); //满了就会等待,程序阻塞 //strs.add("aaa"); //strs.offer("aaa"); //strs.offer("aaa", 1, TimeUnit.SECONDS); System.out.println(strs); } } TransferQueue  消费者线程先启动,生产者生产一个东西的时候,不是往里扔,首先去找有没有消费者,如果有消费者就直接给消费者。 TransferQueue有一个自身的方法transfer,如果没有消费者,调用transfer,那么就会在这个地方进行阻塞。 主要用于高并发场景 public class T08_TransferQueue { public static void main(String[] args) throws InterruptedException { LinkedTransferQueue<String> strs = new LinkedTransferQueue<>(); /*new Thread(() -> { try { System.out.println(strs.take()); } catch (InterruptedException e) { e.printStackTrace(); } }).start();*/ //strs.transfer("aaa"); strs.put("aaa"); new Thread(() -> { try { System.out.println(strs.take()); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); } } SynchronusQueue 同步Queue, 是一种特殊的TransferQueue,是容器量为0的queue。 来的任何东西,消费者必须马上消费,如果不消费就阻塞。 这地方只能调用put,不能调用add。put在这里是阻塞等待消费者进行消费。 public class T09_SynchronusQueue { //容量为0 public static void main(String[] args) throws InterruptedException { BlockingQueue<String> strs = new SynchronousQueue<>(); new Thread(()->{ try { System.out.println(strs.take()); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); strs.put("aaa"); //阻塞等待消费者消费 //strs.add("aaa"); System.out.println(strs.size()); } } DelayQueue 执行定时人任务,无界队列。 每一个元素都记录着还有多长时间才可以被消费者来拿。 这个队列默认是排好顺序的,等待时间最长的在最前面,先往外拿。 public class T07_DelayQueue { static BlockingQueue<MyTask> tasks = new DelayQueue<>(); static Random r = new Random(); static class MyTask implements Delayed { long runningTime; MyTask(long rt) { this.runningTime = rt; } @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 long getDelay(TimeUnit unit) { return unit.convert(runningTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS); } @Override public String toString() { return "" + runningTime; } } public static void main(String[] args) throws InterruptedException { long now = System.currentTimeMillis(); MyTask t1 = new MyTask(now + 1000); MyTask t2 = new MyTask(now + 2000); MyTask t3 = new MyTask(now + 1500); MyTask t4 = new MyTask(now + 2500); MyTask t5 = new MyTask(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++) { System.out.println(tasks.take()); } } }

转载请注明原文地址: https://www.6miu.com/read-47370.html

最新回复(0)