【前言】
这是实际工作中某任务的简化版,实际任务是将A库a表的数据迁移到B库b表,需要启动多线程进行迁移,全部迁移完毕后更改某表某记录的状态和数量字段。
例程进行了简化处理以方便理解。
【实现】
利用固定线程池限流,利用CoutDownLatch来通知计数线程进行统计。
【代码】
数据库实用类:
package com.hy.lab.countdown; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DbUtil { public static Connection getConnection() { Connection conn = null; try { Class.forName("oracle.jdbc.driver.OracleDriver"); String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl"; String user = "luna"; String pass = "1234"; conn = DriverManager.getConnection(url, user, pass); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } return conn; } }
插值线程:
package com.hy.lab.countdown; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.concurrent.CountDownLatch; public class InsertThread implements Runnable{ private int min; private int max; private CountDownLatch cdl; public InsertThread(int min,int max,CountDownLatch cdl){ this.min=min; this.max=max; this.cdl=cdl; } @Override public void run() { String insertSql="insert into emp69(id,name) values (?,?)"; try(Connection conn=DbUtil.getConnection(); PreparedStatement pstmt =conn.prepareStatement(insertSql)){ conn.setAutoCommit(false); for(int i=min;i<max;i++){ pstmt.setLong(1,i); pstmt.setString(2,"Name:"+i); pstmt.addBatch(); } pstmt.executeBatch(); conn.commit(); cdl.countDown(); }catch (Exception ex){ ex.printStackTrace(); } } }
计数线程:
package com.hy.lab.countdown; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.concurrent.CountDownLatch; public class Counter extends Thread{ private CountDownLatch cdl; public Counter(CountDownLatch cdl){ this.cdl=cdl; } public void run(){ try { cdl.await(); printTotal(); } catch (InterruptedException e) { e.printStackTrace(); } } private void printTotal(){ String sql="select count(*) from emp69"; try(Connection conn=DbUtil.getConnection(); PreparedStatement pstmt =conn.prepareStatement(sql); ResultSet rs=pstmt.executeQuery()){ while(rs.next()){ int count=rs.getInt(1); System.out.println("多线程插值后emp69表总数="+count); return; } }catch (Exception ex){ ex.printStackTrace(); } } }
使用代码:
package com.hy.lab.countdown; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Test { public static void main(String[] args){ final int TH_COUNT=10;// 线程数10 CountDownLatch cdl=new CountDownLatch(TH_COUNT); new Counter(cdl).start(); ExecutorService es= Executors.newFixedThreadPool(5);// 并发数5 for(int i=0;i<TH_COUNT;i++){ int min=i*100; int max=(i+1)*100; es.submit(new InsertThread(min,max,cdl)); } es.shutdown(); } }
【运行情况】
多线程插值后emp69表总数=1000
【使用到的表结构】
create table emp69( id number(12), name nvarchar2(20), primary key(id));
【参考资料】
《Java多线程与线程池计数详解》 肖海鹏 牟东旭著 清华大学出版社出版
END