基于XML的数据库开发-8
2013-11-12 21:44
399 查看
这几天正在看<<Java并发编程实战>>.对于多线程操作有了新的认识.下面介绍一下关于串行转并行的处理.
为了保证客户端修改数据不会影响到服务端的原始数据,LocalXData在返回搜查结果的时候,会做一次深拷贝.调用的函数如下:
可以看出,如果数据较多的情况下,调用这个函数复制这个数据就会相当耗时.相关代码如下;
如果使用多线程处理的话,就可以并行处理copy的操作,而不是如上代码,逐个copy了。具体代码如下:
其中需要注意一点的是:由于Arraylist不是线程安全的,所以如果在多线程同时操作的时候,可能会造成数据丢失(实测的确发生了,50000个数据大约丢失了300个)
所以这里使用了ConcurrentLinkedQueue。
实测50000条数据如果使用循环copy的情况下耗时0.4S
实测50000条数据如果使用多线程copy的情况下耗时0.16S
为了保证客户端修改数据不会影响到服务端的原始数据,LocalXData在返回搜查结果的时候,会做一次深拷贝.调用的函数如下:
public static Object copyObj(Object obj) { Object retdata = null; try { Class clazz = Class.forName(obj.getClass().getName()); Constructor[] constructorList = clazz.getDeclaredConstructors(); Constructor constructor = constructorList[0]; constructor.setAccessible(true); Object membet = constructor.newInstance(); Field[] fieldlist = obj.getClass().getDeclaredFields(); for(Field field:fieldlist) { switch (PraseParamUtil.PraseObjectType(field.getType().getName())) { case PraseParamUtil.PRASE_TYPE_INT: Field intField = membet.getClass().getField(field.getName()); intField.setInt(membet, field.getInt(obj)); break; case PraseParamUtil.PRASE_TYPE_BOOLEAN: Field booleanField = membet.getClass().getField(field.getName()); booleanField.setBoolean(membet, field.getBoolean(obj)); break; case PraseParamUtil.PRASE_TYPE_FLOAT: Field floatField = membet.getClass().getField(field.getName()); floatField.setFloat(membet, field.getFloat(obj)); break; case PraseParamUtil.PRASE_TYPE_LONG: Field longField = membet.getClass().getField(field.getName()); longField.setLong(membet, field.getLong(obj)); break; case PraseParamUtil.PRASE_TYPE_STRING: Field stringField = membet.getClass().getField(field.getName()); stringField.set(membet, field.get(obj)); break; } } return membet; } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } return retdata; }
可以看出,如果数据较多的情况下,调用这个函数复制这个数据就会相当耗时.相关代码如下;
if(dataList != null) { dataList.enterLooper(); for(DataCell dataCell :dataList) { if(dataCell.getState() != DataCell.DATA_DELETE) { list.add(SqlUtil.copyObj(dataCell.obj)); } } dataList.leaveLooper(); }
如果使用多线程处理的话,就可以并行处理copy的操作,而不是如上代码,逐个copy了。具体代码如下:
final Queue<Object>queue = new ConcurrentLinkedQueue<Object>(); //wangsl use parallel ExecutorService exec = Executors.newFixedThreadPool(10); if(dataList != null) { dataList.enterLooper(); for(DataCell dataCell :dataList) { final DataCell cell = dataCell; if(dataCell.getState() != DataCell.DATA_DELETE) { //list.add(SqlUtil.copyObj(dataCell.obj)); exec.execute(new Runnable() { @Override public void run() { queue.add(SqlUtil.copyObj(cell.obj)); } }); } } dataList.leaveLooper(); } //wangsl use parallel exec.shutdown(); try { exec.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }
其中需要注意一点的是:由于Arraylist不是线程安全的,所以如果在多线程同时操作的时候,可能会造成数据丢失(实测的确发生了,50000个数据大约丢失了300个)
所以这里使用了ConcurrentLinkedQueue。
实测50000条数据如果使用循环copy的情况下耗时0.4S
实测50000条数据如果使用多线程copy的情况下耗时0.16S