一.背景
多线程写入到一个集合中,当集合大于N时,flush当前集合,并且用一个新的集合代替写入,不能全局加锁
二.实现
1. 如果全局加锁,那么可以先在写入前判断集合大小,然后再插入,但是不加锁,先判断集合大小,再插入可能会导致多个线程同时拿到集合大小满足条件的值,插入后超过集合大小,比如
List list;
void put(int value){
1. if(list.size<10){
2. list.put(valus);
}
}
3个线程走到1处,size都为9,然后再都执行2,size会超过10
2.如果预先判断坑位,有坑位再写入,没有就flush
AtomicInteger preWrite;
void put(int value){
int count=preWrite.incrementAndGet();
1. if(count>10){
synchronized{
flush(list);
list=new ArrayList();
preWrite.set(0);
}
2. preWrite.incrementAndGet();
}
list.write(value);
}
}
代码2处的原因是经过if之后,preWrite的预占位被清掉了进行补偿
可能出现的问题:
- 线程A count=11
- 线程B count=5 然后让出cpu停留在代码1处
- 这时候A进行flush,list的大小就只有9
- 下一个list可能就有11这么大
3.加入写完判断
AtomicInteger preWrite;
AtomicInteger afterWrite;
void put(int value){
1. int count=preWrite.incrementAndGet();
if(count>10){
synchronized{
while(afterWrite.get()!=10)
Thread.sleep(0);
flush(list);
list=new ArrayList();
2. preWrite.set(0);
afterWrite.set(0);
}
preWrite.incrementAndGet();
}
list.write(value);
afterWrite..incrementAndGet();
}
}
- 假设线程A运行到代码2处
- 线程B运行到代码1处然后执行完put
- 这时候线程A继续执行,afterWrite会被置为0
- 这样导致的问题是after少了一次,while会被一直卡住
4.调整顺序
AtomicInteger preWrite;
AtomicInteger afterWrite;
void put(int value){
1. int count=preWrite.incrementAndGet();
if(count>10){
synchronized{
while(afterWrite.get()!=10)
Thread.sleep(0);
flush(list);
list=new ArrayList();
2. afterWrite.set(0);
preWrite.set(0);
}
preWrite.incrementAndGet();
}
list.write(value);
afterWrite..incrementAndGet();
}
}
始终让after小于pre 结果发现还会卡在while里面,并且after是11 这里有个漏洞if就完事了,有点
if(a>10)
wait();
的感觉,唤醒后一定要check 所以最终改为
private AtomicInteger preWrite = new AtomicInteger();
private AtomicInteger afterWrite = new AtomicInteger();
int batch = 10000;
Queue<Integer> list = new ConcurrentLinkedQueue<>();
void put(int value) throws InterruptedException {
int count = preWrite.incrementAndGet();
while (count > batch) {
synchronized (this) {
if (preWrite.get() > batch) {
while (afterWrite.get() != batch)
Thread.sleep(0);
list = new ConcurrentLinkedQueue();
afterWrite.set(0);
preWrite.set(0);
}
count = preWrite.incrementAndGet();
}
}
list.add(value);
afterWrite.incrementAndGet();
}
ConcurrentLinkedQueue这个数据结构使用有问题
int[] list = new int[batch];
static final int testCount = 1000000;
void put(int value) throws InterruptedException {
int count = preWrite.incrementAndGet();
while (count > batch) {
synchronized (this) {
if (preWrite.get() > batch) {
while (afterWrite.get() != batch)
Thread.sleep(0);
list = new int[batch];
afterWrite.set(0);
preWrite.set(0);
}
count = preWrite.incrementAndGet();
}
}
list[count - 1] = value;
afterWrite.incrementAndGet();
}
因为count预先占位了