【Java线程】使用十个线程往某表插值,允许并发数5,执行完毕后让计数线程去统计数量。


【前言】

这是实际工作中某任务的简化版,实际任务是将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){
                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){
            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

相关