一:本人使用的环境
jdk1.7+window 10 + oracle 11g
二:使用的技术
1:阻塞队列(BlockingQueue):先进先出(FIFO),生产者-消费者的模式
分为有界队列(ArrayBlockingQueue)、无界队列(linkedBlocingQueue)等,其他的不在此举例
其put()方法:如果队列已满则阻塞,直到队列中减少,才能被唤醒其线程,有机会去争取资源,继续添加元素到队列中。
其take()方法:如果队列中没有元素,则阻塞该线程,直到阻塞队列中put元素到队列中,才能被唤醒线程。
2:使用ForkJoinPool框架:一种将大任务分割成若干的小任务来执行,至于分成多少个,设置其阀值,比如阀值为100,如果小于100,则不分割,超过100,就再次的分 割,其一个重要的特点(也是其框架的一种有效的智能方法来平衡可用线程的工作负载):工作密取(working-stealing),当某个线程的所有任务都现行执行完毕时,就会向其他执行慢的任务队列中偷取任务来完成,从队列的尾部来偷取,(该队列使用的是双端队列),正常情况下都是从队列头部来取任务来执行,只有工作窃取的时候才会从队列的尾部来取任务,需要继承一个计算合并结果的RecursiveTask
其缺点是:因为产生大量的子任务,结束后,GC的时长会长,大概1s多。
3:使用线程池(ThreadPoolExecutor):可以很大的程度上减少传统的新建(new Thread)以及销毁而带来的性能降低和内存资源消耗的开销。(接口ExecutorService可以执行线程)
1.newFixedThreadPool(int)可以指定固定的线程数,操作无界队列
2.newScheduleThreadPool(int corePoolsize):可以调度一个在给定的延迟后运行。
3.newSingleThreadPool():创建一个单一的线程来执行。
4.newCacheThreadPool():根据需要来创建新的线程,但在可用时将重用先前的构建的线程。
三:使用阻塞队列时:
ExecutorService executorService = Executors.newFixedThreadPool(10);
BlockingQueue
BlockQueuThread aa = new BlockQueuThread(queue, randomCodeSeg);
executorService.execute(aa);
SegCodeQueueThread codeQueue = null;
for(int i =0 ; i<4;i++){
codeQueue = new SegCodeQueueThread(baseCdsService,codeSegmentDao, codePoolBean, queue);
executorService.execute(codeQueue);
}
BlockQueuThread 读入到队列中的run方法体:
int siez = randomCodeSeg.size();
String aa = "end";
try {
for(int i = 0 ; i< siez ; i++ ){
queue.put(randomCodeSeg.get(i));
System.out.println("线程name:"+Thread.currentThread().getName()+"-->该线程状态:"+Thread.currentThread().getState()+"queue队列长度:"+queue.size());
}
queue.put(aa);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
e.printStackTrace();
SegCodeQueueThread中的run方法体:
boolean bo = false;
// final LinkedList
执行92万条数据,纯插入单张表,但是执行到一定的时候,线程发生死锁;锁死的错误如下:
问题定位:从上面已锁定可以看出,在操作IO的时候出现死锁,在网上搜索下, 原因是system.out.print()的问题,在多线程使用的情况下, 出现这种情况,
有使用log4j,也会log。info()出现问题。
问题解决:将所有执行的操作中去掉system打印语句。
可参考文章:http://blog.csdn.net/qq_24504453/article/details/75028213
使用forkJoinPool框架的时候,同样的批量导入操作,经本人多次的测试,没有发生异常,每秒达到680次。
继承两种方式:一种有返回值的,合并所有的子任务后返回数据(RecursiveTask),还有一种没有返回数据的
(RecursiveAction)
代码如下:
ForkJoinPool forkJoinPool = new ForkJoinPool();
SegCodeTask codeTask = new SegCodeTask(baseCdsService,codeSegmentDao, codePoolBean, randomCodeSeg, 0, randomCodeSeg.size());
// forkJoinPool.execute(codeTask);
Integer invoke = forkJoinPool.invoke(codeTask);
System.out.println("获取已启动但是还未执行完成的线程数目:"+forkJoinPool.getPoolSize());
System.out.println("获取由工作线程队列中的任务总数的计算:"+forkJoinPool.getQueuedTaskCount());
System.out.println("获取从一个线程被另一个线程窃取的总任务数:"+forkJoinPool.getStealCount());
System.out.println("获取活动的线程数目:"+forkJoinPool.getActiveThreadCount());
System.out.println("总任务执行数目:"+invoke);
@Override
protected Integer compute() {
if(end - begin <= mid){
LinkedList
特别注意,上述的操作都是使用SPRING 中的jdbc,使用批量插入batchInsert以及单条插入
但是使用mybatis中sqlSession交互数据库,却发现92万根本无法导入成功,都会在几万的时候会锁死,也使用过动态sql的foreach作导入,也不尽人意
不知道是否是mybatis就不支持大批量的导入操作呢?还是sqlsession连接数问题?