Map or Set
-
并发要求低时加锁容器类:
Hashtable //用的少
Collections.sychronizedMap(new HashMap())
Collections.sychronizedList ...
例:List<String> strsSync = Collections.synchronizedList(new ArrayList());
并发要求高时加锁容器类:
ConcurrentHashMap
分段加锁(大锁分成小锁)。不同块之间可以同时执行
并发要求高并需要排序:
ConcurrentSkipListMap
跳表查询,查找效率高。跳表:每个元素上有多个指针,指向后面多个节点,进行跳跃查询。比如查找 19.从6 开始比较。大于6.直接跳到9.越过了7.从时间复杂度来讲。从O(n)变为了O(n/2)
队列
Collections.synchronizedXXX
CopyOnWriteList:
写时复制容器。写时效率很低。读时效率高。写时加锁,读不加锁。写的时候复制一份数据,并在这份数据上做更改,再把指针指向换到新数据中。读写分离的思路。
Queue: 分两种:1.加锁的Queue 2.Blocking Queue
-
CocurrentLinkedQueue //concurrentArrayQueue
例:
Queue<String> strs = new ConcurrentLinkedQueue<>();
for(int i=0; i<10; i++) {
strs.offer("a" + i); //add 有boolean返回值来判断插入是否成功
}
System.out.println(strs.size()); //10
System.out.println(strs.poll());//a0 ;拿取第一个。并删除。先进先出
System.out.println(strs.size());//9
System.out.println(strs.peek());//a1 ;拿取第一个。不删除
System.out.println(strs.size());// 9
-
BlockingQueue:阻塞队列
LinkedBlockingQueue
ArrayBlockingQueue
例:
public class LinkedBlockingQueue {
static BlockingQueue<String> strs = new LinkedBlockingQueue<>(10);
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); //如果满了,就会等待
System.out.println("now size:"+strs.size()); //永远不会超过10个长度
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()); //如果空了,就会等待。不会出现IndexOutOfBoundException
TimeUnit.MILLISECONDS.sleep(r.nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "c" + i).start();
}
}
}
往容器内加入方法有多个,如下
strs.put("aaa"); //满了就会等待,程序阻塞
strs.add("aaa"); //报异常
strs.offer("aaa"); //不会报异常。只会在返回值中返回true or false
strs.offer("aaa", 1, TimeUnit.SECONDS);//等待一秒再加入
TransferQueue :队列有消费者等待消费时,直接把信息给消费者,不进入队列,高并发下效率更高,适用于游戏服务器接收,转发消息。如果没有消费者等待消费该队列,这时strs.transfer("aaa"); 线程将阻塞。但是put add 方法都不会阻塞。netty中使用比较多,很多实时消息需要强制被消费之后才执行下面操作。
SynchronusQueue : 容量为0,只能调用strs.put("aaa") 进行加入,目的是为了进入阻塞状态,等待被消费。是必须被消费的,不能存在队列中。如调用add()将提示队列已满
DelayQueue : 可作为执行定时任务 按指定的时间,顺序消费,delay时间越短的越早消费