如何高性能操作list

09-12-07 xysniper
现在有一个list,多个线程并发访问,有的线程add,有的线程get,请问有什么方法保证这个list数据同步及高性能

我试过了,使用synchronized和ReentrantLock性能都不是很高

1
banq
2009-12-07 17:06
如果是以读为主,以写为辅助,可以使用读写锁,readwritelock

xysniper
2009-12-07 18:26
我的设计如下:

提取数据线程:1

作用:将xml数据压入ConcurrentLinkedQueue队列

分发线程

数量:3

作用:从ConcurrentLinkedQueue取数据,select db后,将其数据根据特点插入两个不同的java.util.ArrayList中

处理线程

数量:1

作用:从上面的ArrayList中取出使用ibatis的batch insert or batch

update插入或更新到数据库中

性能如下:

入库数据:603~644条/分钟

前提:我的ArrayList中使用了ReentrantReadWriteLock控制同步,代码如下:

总结:是不是读写锁性能不可观呢?多线程后还不如单线程快呀

/**
 * 
 */
package util;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.apache.log4j.Logger;

import vo.SubscriberState;

public class DataPersistenceQueue implements PersistenceQueue {
	private final ReentrantReadWriteLock rwlfi = new ReentrantReadWriteLock();
	private final ReentrantReadWriteLock rwlfu = new ReentrantReadWriteLock();
	private final Lock ri = rwlfi.readLock();
	private final Lock wi = rwlfi.writeLock();
	private final Lock ru = rwlfu.readLock();
	private final Lock wu = rwlfu.writeLock();
	private Logger log = Logger.getLogger(DataPersistenceQueue.class);
	private List insertList = new ArrayList();
	private List updateList = new ArrayList();
	private boolean isStop = false;

	public DataPersistenceQueue() {
		isStop = false;
	}

	public void insertList(SubscriberState substate) {
		wi.lock();
		try {
			insertList.add(substate);
		} finally {
			wi.unlock();
		}
	}
	
	/**
	 * @return the insertQueue
	 */
	public List<SubscriberState> getInsertList() {
		ri.lock();
		try {
			return new ArrayList(insertList);
		} finally {
			insertList.clear();
			ri.unlock();
		}
	}
	

	public void updateList(SubscriberState substate) {
		wu.lock();
		try {
			updateList.add(substate);
		} finally {
			wu.unlock();
		}
	}

	/**
	 * @return the updateQueue
	 */
	public List<SubscriberState> getUpdateList() {
		ru.lock();
		try {
			return new ArrayList(updateList);
		} finally {
			updateList.clear();
			ru.unlock();
		}
	}


	/*
	 * (non-Javadoc)
	 * 
	 * @see util.PersistenceQueueisEmpty()
	 */
	public boolean isEmpty() {
		return insertList.isEmpty() && updateList.isEmpty();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see util.PersistenceQueueisStop()
	 */
	public boolean isStop() {
		return isStop;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see util.PersistenceQueuesetStop()
	 */
	public void stopQueue() {
		this.isStop = true;
	}

	/* (non-Javadoc)
	 * @see util.PersistenceQueuegetInsertListSize()
	 */
	public int getInsertListSize() {
		// TODO Auto-generated method stub
		return insertList.size();
	}

	/* (non-Javadoc)
	 * @see util.PersistenceQueuegetUpdateListSize()
	 */
	public int getUpdateListSize() {
		// TODO Auto-generated method stub
		return updateList.size();
	}
}

<p>

[该贴被xysniper于2009-12-07 18:40修改过]

banq
2009-12-08 09:39
你如果是读取整个List,就不必用读写锁,可以参考LinkedBlockingQueue,使用事件Queue异步就可以了,

参考事件模式

推荐你从模式角度考虑,是这样可以理清思路。

xysniper
2009-12-08 10:52
To banq

需要读写锁的,因为一个线程不断地写入这个List,另外一个线程不断地

从List中拿数据,拿走入库后必须将List清空访止同一条数据重复拿走入库,造成数据库中同一条数据重复多次写入,所以才加入同步控制

上面的测试是在我本地,将其放入linux测试机,测式性能还是可以的:

91770条入库/分钟,说明多线程只有在硬件足够强,cpu多的情况下才发挥作用,否则反而更慢

你说的LinkedBlockingQueue我会看一下

[该贴被xysniper于2009-12-08 10:55修改过]

banq
2009-12-08 13:22
2009年12月08日 10:52 "xysniper"的内容
To banq

需要读写锁的,因为一个线程不断地写入这个List,另外一个线程不断地

从List中拿数据,拿走入库后必须将List清空访止同一条数据重复拿走入库,造成数据库中同一条数据重复多次写入,所以才加入同步控制

你的这个情形是典型异步观察者Queue模式,可以使用LinkedBlockingQueue完成。再往大扩展,可使用JMS。

别忘记使用ThreadPoolExecutor之类,性能要更快些:

ExecutorService executor = new ThreadPoolExecutor(numberOfThreads, numberOfThreads, //
    60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());

<p>

[该贴被banq于2009-12-08 14:09修改过]

xysniper
2009-12-09 12:33
是使用了ThreadPoolExecutor,用的是ArrayBlockingQueue,不知两个性能哪个高?没有测试过

zdbj2ee
2009-12-29 11:21
看看CopyOnWriteArrayList

tuhaitao
2010-01-09 01:41
建议你看下,是否在已经建立索引的表上 进行插入,那样会很慢

chenyongcan
2010-01-14 23:07
优化七:一条sql插入多个值。

继续的插入优化,插入经过上次的优化之后,又开始了下一轮的优化。这次着重在如何提高数据库的写入速度。开始我们为了加快插入速度,使用的是iBATIS的批量提交,从理论上讲应该会比一条条的插入快,因该是常识吧。但是这次事实上告诉我,仅仅是把批量提交去掉就已经提高了3倍多,更牛B的在后面。

陶方建议一个sql插入多个值,形如insert into tableName (x,xx,xxx) values(x,xx,xxx),(xx,xxx,xxxx)…,经过这样修改之后,在我看来,速度已经很疯狂了.

猜你喜欢