一、
有N张火车票,多线程售票
1、放arraylist ,销售一张remove()一次 出现 重卖,超卖
2、放Vector ,调用remove ,问题依旧,因为虽然集合vector的判断和remove为原子性
但是放一起执行 中间的调用代码无法保持原子性,
3、加入sycnize,锁住当前对象,问题解决,但效率低
4、使用队列 static Queue<String> tickets = new ConcurrentLinkedQueue<>();
支持多线程,调用String s = tickets.poll();判断s==null;break; 判断完之后没有对队列进行操作,不会出现问题,而且没有加锁,效率高
二、多线程什么容器效率比较高
map的key即使用set实现
ConcurrentHashMap 分段锁,锁定一部分(8分之一)对象,锁粒度小 效率高
ConcurrentSkipListMap 跳表 高并发并且排序 效率低,查询排序快
HashTable 锁定整个容器对象 中
三、CopyOnWriteArrayList 写实复制。先复制一份,再操作,读不用加锁,写的效率低 适合写的很少读的很多的场景,比如事件监听器
四、ConcurrentLinkedQueue 并发加锁
Queue<String> strs = new ConcurrentLinkedQueue<>();
strs.offer 添加
strs.poll 拿出第一个同时删除改元素
strs.peek 拿出但是不删除
都返回是否操作成功的结果
Deque 双向队列 队列头尾都可以添加跟拿出
五、BlockingQueue 阻塞式
1、LinkedBlockingQueue 的strs.put 如果满了,就会等待 strs.take 如果空了,就等待,无界队列
2、ArrayBlockingQueue 有界队列 strs.add超出长度也就是越界 报异常,offer不会报,但也不会加入成功 strs.put 满了就会等待,程序阻塞
3、DelayQueue 每个元素还有多久时间可以取
场景:定时执行任务
使用之前需实现接口Delay
4、LinkedTransferQueue 高并发
消费者 提供者线程中,一般是提供者提供资源到队列,消费者从队列获取,但是transferQueue的话如果提供者发现有消费者等待,不用放队列,直接给消费者。实时处理
5、SynchronousQueue同步队列 特殊的TransferQueue
容量为0。
不能调用add,用put,不能存元素,而是直接交给消费者