多线程,内存存放数据检验

背景:为提高帐户校验效率,将原来的数据库检验方式变更为将数据存于内存,动态变更内存数据,检验取内存数据的方式,解决检验问题

方案:

  1. 创建对象Map用于存放帐户当前可用金额信息

  2. 检验时,判断金额信息是否存在,存在则使用内存金额进行校验,不存在则查询数据库获取最新的可用金额信息

  3. 检验通过,则更新可用金额

  4.每隔一段时间,对内存消息进行核对,将数据库查询到的信息更新到内存中

关键点实现:

  1. 存放帐户可用金额的对用,必须是线程安全的,使用ConcurrentHashMap,可以在保证效率的同时做到线程安全。

  eg:

  // 账户可用额度相关信息Map
  public static ConcurrentHashMap<Long,AccountGroupInfo> currentAccountGroupAmountMap = new ConcurrentHashMap<Long,AccountGroupInfo>();

  2. 在对帐户可用额度Map进行操作时,需要进行加锁,保证多线程调用时的数据正确性,同时为了满足加锁未成功的情况下,可设置等待时间,不让校验操作无限等待。

在Map中设计isLock字段,标志帐户是被锁,进行校验,更新操作时,需要对帐户进行加锁。

  3. 在进行加锁操作时,需要进行同步处理,保证锁的获取是同步的。使用synchronized字段实现锁,但是只对单个的帐户对象进行加锁,保证在同一个帐户的加锁操作上是同步的。

  4. 对加锁操作进行尝试次数和等待时间控制,加锁操作可以尝试5次,每次尝试失败等待100毫秒,如果在5次100毫秒内未加锁成功,则抛出异常,将此次的校验置为失败,进行下次操作

  eg:

synchronized (accountGroupInfo) {
            boolean lockSuccess = false;
            for(int i=0;i<5;i++){
                System.out.println(Thread.currentThread().getName()+"尝试加锁次数"+(i+1)+"==========laccountid============"+laccountid);
                if(!accountGroupInfo.isLock()){
                    accountGroupInfo.setLock(true);
                    lockSuccess = true;
                    System.out.println("---------------加锁成功"+Thread.currentThread().getName()+"==========laccountid============"+laccountid);
                    break;
                }else{
                    Thread.sleep(100);
                }
            }
            if(!lockSuccess){
                System.out.println("加锁失败"+Thread.currentThread().getName()+"==========laccountid============"+laccountid);
                throw new Exception("加锁失败");
            }
        }

附:

  1.对象加锁

       String key = getKey();
       Object object = getLock(key);
       synchronized (object ) {
             // 逻辑处理代码
       }
        /**
     * 得到对象锁
     */
    private static Object getLock(Long key){
        Object value = new Object();
        Object v = locks.putIfAbsent(key, value);
        if(v == null){
            return value;
        }
        return v;
    } 

  

  2. 锁逻辑原则

  3. 整体代码实现

package com.iss.itreasury.accountgroup;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.concurrent.ConcurrentHashMap;

import com.iss.itreasury.settlement.base.SettlementException;
import com.iss.itreasury.settlement.setting.dao.SettAccountGroupSettingDao;
import com.iss.itreasury.settlement.util.UtilOperation;
import com.iss.itreasury.util.DataFormat;
import com.iss.itreasury.util.Database;
import com.iss.itreasury.util.Env;

public class AccountGroupOperation {

    // 账户与账户组的关联关系
    public static ConcurrentHashMap<Long,Long> accountGroup = new ConcurrentHashMap<Long,Long>();

    // 账户组可用额度相关信息Map
    public static ConcurrentHashMap<Long,AccountGroupInfo> currentAccountGroupAmountMap = new ConcurrentHashMap<Long,AccountGroupInfo>();

    // 帐户组锁
    public static ConcurrentHashMap<Long, Object> locks = new ConcurrentHashMap<Long, Object>();

    /**
     *  判断该账户所在账户组本区间是否透支
     * @param 账户ID,支付金额
     * @return 透支true   不透支false
     * @throws Exception
     * */
    public static boolean isOverDraftAccgroup(long laccountid,double payamount,long lOfficeID,long lCurrencyID) throws Exception{

        return isOverDraftAccgroup(laccountid, payamount, lOfficeID, lCurrencyID,false);
    }

    /**
     *  判断该账户所在账户组本区间是否透支
     * @param 账户ID,支付金额
     * @return 透支true   不透支false
     * @throws Exception
     * */
    public static boolean isOverDraftAccgroup(long laccountid,double payamount,long lOfficeID,long lCurrencyID,boolean isEbank) throws Exception{
        boolean flag = false;
        // 开机日期
        Timestamp systemDate = Env.getSystemDate(lOfficeID, lCurrencyID);
        SettAccountGroupSettingDao dao = new SettAccountGroupSettingDao();
        // 1. 帐户是否加入了帐户组
        long accountGroupId;
        // 如果账户与帐户组关联关系没有,进行初始化
        if(isEbank){
            accountGroup = new ConcurrentHashMap<Long,Long>();
        }
        if(accountGroup.size()==0){
            AccountGroupOperation.init();
        }
        try {
            // 1.1 获取帐户组ID
            accountGroupId = findAccountGroup(laccountid);
        } catch (Exception e1) {
            e1.printStackTrace();
            throw new Exception("获取帐户组关系失败");
        }
        // 1.2 帐户不在帐户组中,无需校验
        if(accountGroupId == -1){
            System.out.println("帐户:"+laccountid+"不在帐户组中,无需校验");
            return false;
        }
        Object lock = getLock(accountGroupId);
        // 2. 内存currentAccountGroupAmountMap中是否存在该账户组可用额度相关信息
        synchronized (lock) {
            if(currentAccountGroupAmountMap.get(accountGroupId)==null||isEbank){
                System.out.println("==================账户组可用额度Map初始化==================");
                // 2.1 账户组额度信息初始化
                AccountGroupInfo accountGroupInfo = new AccountGroupInfo();
                accountGroupInfo.setLock(false);
                accountGroupInfo.setLimitAmount(-1);
                accountGroupInfo.setLimitDate(systemDate);
                boolean isAccgroupBudget = false;
                try {
                    // 账户是否加入账户组且该年月设置了账户组额度
                    isAccgroupBudget = dao.CheckAccgroupExistBudget(laccountid, accountGroupInfo.getLimitDate()) > 0;
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new Exception("账户是否加入账户组且该年月设置了账户组额度校验失败");
                }
                accountGroupInfo.setAccgroupBudget(isAccgroupBudget);
                currentAccountGroupAmountMap.put(accountGroupId, accountGroupInfo);
            }
        }
        AccountGroupInfo accountGroupInfo = currentAccountGroupAmountMap.get(accountGroupId);
        // 3    额度校验 是否设置了预算
        // 如果月份发生改变,对是否设置预算进行重新赋值
        if(!(DataFormat.getRealMonthString(accountGroupInfo.getLimitDate()).equals(DataFormat.getRealMonthString(systemDate))&&DataFormat.getYearString(accountGroupInfo.getLimitDate()).equals(DataFormat.getYearString(systemDate)))){
            boolean isAccgroupBudget = dao.CheckAccgroupExistBudget(laccountid, accountGroupInfo.getLimitDate()) > 0;
            accountGroupInfo.setAccgroupBudget(isAccgroupBudget);
            // 有变成无,移除缓存内容
            if(accountGroupInfo.isAccgroupBudget()&&!isAccgroupBudget){
                currentAccountGroupAmountMap.remove(accountGroupId);
                System.out.println("帐户:"+laccountid+"不需要进行账户组额度校验");
                return false;
            }
        }
        if(!accountGroupInfo.isAccgroupBudget()){
            System.out.println("帐户:"+laccountid+"不需要进行账户组额度校验");
            return false;
        }
        // 4.帐户组加锁
        synchronized (accountGroupInfo) {
            boolean lockSuccess = false;
            for(int i=0;i<5;i++){
                System.out.println(Thread.currentThread().getName()+"尝试加锁次数"+(i+1)+"==========laccountid============"+laccountid);
                if(!accountGroupInfo.isLock()){
                    accountGroupInfo.setLock(true);
                    lockSuccess = true;
                    System.out.println("---------------加锁成功"+Thread.currentThread().getName()+"==========laccountid============"+laccountid);
                    break;
                }else{
                    Thread.sleep(1000);
                }
            }
            if(!lockSuccess){
                System.out.println("加锁失败"+Thread.currentThread().getName()+"==========laccountid============"+laccountid);
                throw new Exception("加锁失败");
            }
        }
        // 4.2 额度校验 额度核对(如果“当前可用额度”为-1或“额度日期”不等于开机日或“更新时间”与当前应用服务器时间差值超过1个小时,则执行核对逻辑)
        try{
            checkAccountGroup(accountGroupId,lOfficeID,lCurrencyID);
        }catch (Exception e) {
            e.printStackTrace();
            if(accountGroupInfo.isLock()){
                accountGroupInfo.setLock(false);
            }
            throw new Exception("帐户组额度核对失败");
        }
        // 4.3 额度校验
        System.out.println("======占用前======");
        System.out.println("账户ID======"+laccountid);
        System.out.println("账户组ID======"+accountGroupId);
        System.out.println("账户组可用金额======"+DataFormat.formatNumber(accountGroupInfo.getLimitAmount(),2));

        if(UtilOperation.Arith.sub(payamount, accountGroupInfo.getLimitAmount()) > 0 ){
            if(accountGroupInfo.isLock()){
                accountGroupInfo.setLock(false);
            }
            System.out.println("帐户组透支---------------解锁成功"+Thread.currentThread().getName()+"==========laccountid============"+laccountid);
            return true;
        }

        // 5  额度占用
        accountGroupInfo.setLimitAmount(UtilOperation.Arith.sub(accountGroupInfo.getLimitAmount(), payamount));
        accountGroupInfo.setUpdateTime(new Timestamp(System.currentTimeMillis()));

        System.out.println("======占用后======");
        System.out.println("账户ID======"+laccountid);
        System.out.println("账户组ID======"+accountGroupId);
        System.out.println("账户组可用金额======"+DataFormat.formatNumber(accountGroupInfo.getLimitAmount(),2));

        // 6  帐户组解锁
        if(accountGroupInfo.isLock()){
            accountGroupInfo.setLock(false);
        }
        System.out.println("---------------解锁成功"+Thread.currentThread().getName()+"==========laccountid============"+laccountid);
        return flag;
    }

    /**
     *  释放账户组额度
     * @param 账户ID,释放金额
     * @throws Exception
     * */
    public static void releaseDraftAccgroup(long laccountid,double payamount) throws Exception{

        // 1. 帐户是否加入了帐户组
        long accountGroupId;
        try {
            // 1.1 获取帐户组ID
            accountGroupId = findAccountGroup(laccountid);
        } catch (Exception e1) {
            e1.printStackTrace();
            throw new Exception("获取帐户组关系失败");
        }
        // 1.2 帐户不在帐户组中,无需校验
        if(accountGroupId == -1){
            System.out.println("帐户:"+laccountid+"不在帐户组中");
            return;
        }
        AccountGroupInfo accountGroupInfo = currentAccountGroupAmountMap.get(accountGroupId);
        // 没有缓存无需释放
        if(accountGroupInfo==null){
            System.out.println("账户组:"+accountGroupId+"没有缓存无需释放");
            return;
        }
        // 2  额度校验 是否设置了预算
        if(!accountGroupInfo.isAccgroupBudget()){
            System.out.println("账户组:"+accountGroupId+"没有设置预算");
            return;
        }
        // 3   帐户组加锁
        Object lock = getLock(accountGroupId);
        boolean lockSuccess = false;
        synchronized (lock) {
            for(int i=0;i<5;i++){
                System.out.println(Thread.currentThread().getName()+"尝试加锁次数"+(i+1)+"==========laccountid============"+laccountid);
                if(!accountGroupInfo.isLock()){
                    accountGroupInfo.setLock(true);
                    lockSuccess = true;
                    System.out.println("---------------加锁成功"+Thread.currentThread().getName()+"==========laccountid============"+laccountid);
                    break;
                }else{
                    Thread.sleep(1000);
                }
            }
            if(!lockSuccess){
                System.out.println("加锁失败"+Thread.currentThread().getName()+"==========laccountid============"+laccountid);
                throw new Exception("加锁失败");
            }
        }
        System.out.println("======释放前======");
        System.out.println("账户ID======"+laccountid);
        System.out.println("账户组ID======"+accountGroupId);
        System.out.println("账户组可用金额======"+DataFormat.formatNumber(accountGroupInfo.getLimitAmount(),2));

        // 4  可用额度释放
        accountGroupInfo.setLimitAmount(UtilOperation.Arith.add(accountGroupInfo.getLimitAmount(), payamount));

        System.out.println("======释放后======");
        System.out.println("账户ID======"+laccountid);
        System.out.println("账户组ID======"+accountGroupId);
        System.out.println("账户组可用金额======"+DataFormat.formatNumber(accountGroupInfo.getLimitAmount(),2));
        // 5  帐户组解锁
        if(accountGroupInfo.isLock()){
            accountGroupInfo.setLock(false);
        }
    }

    /**
     *  帐户组更新方法
     * @param 账户ID,支付金额
     * @return 透支true   不透支false
     * @throws Exception
     * */
    public static void DraftAccgroupUpdate(long accountGroupId,String year,String month,long lOfficeID,long lCurrencyID) throws Exception{
        // 开机日期
        Timestamp systemDate = Env.getSystemDate(lOfficeID, lCurrencyID);
        SettAccountGroupSettingDao dao = new SettAccountGroupSettingDao();

        // 如果预算不为当前月份
        if(!(DataFormat.getRealMonthString(systemDate).equals(month)&&DataFormat.getYearString(systemDate).equals(year))){
            // 无需通知
            System.out.println("==================预算不为当前月份无需通知==================");
            return;
        }

        Object lock = getLock(accountGroupId);
        // 2. 内存currentAccountGroupAmountMap中是否存在该账户组可用额度相关信息
        synchronized (lock) {
            if(currentAccountGroupAmountMap.get(accountGroupId)==null){
                System.out.println("==================账户组可用额度Map初始化==================");
                // 2.1 账户组额度信息初始化
                AccountGroupInfo accountGroupInfo = new AccountGroupInfo();
                accountGroupInfo.setLock(false);
                accountGroupInfo.setLimitAmount(-1);
                accountGroupInfo.setLimitDate(systemDate);
                boolean isAccgroupBudget = false;
                try {
                    // 账户是否加入账户组且该年月设置了账户组额度
                    isAccgroupBudget = dao.CheckGroupExistBudget(accountGroupId, accountGroupInfo.getLimitDate()) > 0;
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new Exception("账户是否加入账户组且该年月设置了账户组额度校验失败");
                }
                accountGroupInfo.setAccgroupBudget(isAccgroupBudget);
                currentAccountGroupAmountMap.put(accountGroupId, accountGroupInfo);
                return;
            }
        }
        AccountGroupInfo accountGroupInfo = currentAccountGroupAmountMap.get(accountGroupId);
        // 4.帐户组加锁
        synchronized (accountGroupInfo) {
            boolean lockSuccess = false;
            for(int i=0;i<5;i++){
                System.out.println(Thread.currentThread().getName()+"尝试加锁次数"+(i+1)+"==========laccountid============"+accountGroupId);
                if(!accountGroupInfo.isLock()){
                    accountGroupInfo.setLock(true);
                    lockSuccess = true;
                    System.out.println("---------------加锁成功"+Thread.currentThread().getName()+"==========laccountid============"+accountGroupId);
                    break;
                }else{
                    Thread.sleep(1000);
                }
            }
            if(!lockSuccess){
                System.out.println("加锁失败"+Thread.currentThread().getName()+"==========laccountid============"+accountGroupId);
                throw new Exception("加锁失败");
            }
        }
        // 额度更新为-1
        accountGroupInfo.setLimitAmount(-1);
        // 6  帐户组解锁
        if(accountGroupInfo.isLock()){
            accountGroupInfo.setLock(false);
        }
        System.out.println("---------------解锁成功"+Thread.currentThread().getName()+"==========laccountid============"+accountGroupId);
    }
    /**
     * 得到帐户组锁
     */
    private static Object getLock(Long key){
        Object value = new Object();
        Object v = locks.putIfAbsent(key, value);
        if(v == null){
            return value;
        }
        return v;
    }
    /**
     * add by jiecheni 2017-11-02
     * 账户与账户组关联关系初始化
     */
    public static void init() {
        System.out.println("==========================账户与账户组关联关系初始化开始==========================");
        Connection con = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            //先清理缓存
            accountGroup.clear();

            con = Database.getConnection();
            StringBuffer sb = new StringBuffer();
            sb.append(" select a.naccgroupid,a.naccountid from sett_budgetaccassign a where a.nstatusid > 0 ");
            ps = con.prepareStatement(sb.toString());
            rs = ps.executeQuery();
            while (rs.next()) {
                try {
                    accountGroup.put(rs.getLong("naccountid"), rs.getLong("naccgroupid"));
                } catch (NullPointerException e) {
                    continue;
                }
            }
            rs.close();
            rs = null;
            ps.close();
            ps = null;
            con.close();
            con = null;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (rs != null)
                {
                    rs.close();
                    rs = null;
                }
                if (ps != null)
                {
                    ps.close();
                    ps = null;
                }
                if (con != null)
                {
                    con.close();
                    con = null;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        System.out.println("==========================账户与账户组关联关系初始化结束,初始化关系数量=========================="+accountGroup.size());
    }

    /**
     * add by jiecheni 2017-11-02
     * 查询账户是否在账户组
     * @param id
     * @return
     * @throws Exception
     */
    public static long findAccountGroup(long id) throws Exception {
        Long result = null;
        try {
            result = accountGroup.get(Long.valueOf(id));
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("查询出现异常,出错原因:"+e.getMessage(), e);
        }
        return result == null ? -1 : result;
    }

    /**
     * add by jiecheni 2017-11-02
     * 将账户与账户组关联信息存入缓存
     * @param accountId
     * @param accountGroupId
     */
    public static void putAccountGroup(long accountId,long accountGroupId) {
        accountGroup.put(accountId, accountGroupId);
    }

    /**
     * add by jiecheni 2017-11-02
     * 将账户与账户组关联信息从缓存中清除
     * @param accountId
     */
    public static void removeAccountGroup(long accountId) {
        accountGroup.remove(accountId);
    }

    /**
     * 账户组额度核对
     * @param accountGroupId    账户组Id
     * @param lOfficeID            办事处Id
     * @param lCurrencyID        币种id
     * @throws Exception
     */
    public static void checkAccountGroup(long accountGroupId,long lOfficeID,long lCurrencyID) throws Exception{
        int isCheckResult = isCheckAccountGroup(accountGroupId,lOfficeID,lCurrencyID);
        AccountGroupInfo accountGroupInfo = currentAccountGroupAmountMap.get(accountGroupId);
        Timestamp limitDate = accountGroupInfo.getLimitDate();
        if(isCheckResult == 3){
            Timestamp systemDate = Env.getSystemDate(lOfficeID,lCurrencyID);
            double accountGroupAmount = UtilOperation.Arith.sub(queryAccountGroupBudget(accountGroupId,systemDate),queryAccountGroupUsedAmount(accountGroupId,systemDate));
            accountGroupInfo.setLimitDate(systemDate);
            accountGroupInfo.setLimitAmount(accountGroupAmount);
            accountGroupInfo.setUpdateTime(new Timestamp(System.currentTimeMillis()));
            currentAccountGroupAmountMap.put(accountGroupId, accountGroupInfo);
        }else if(isCheckResult > 0){
            double accountGroupAmount = UtilOperation.Arith.sub(queryAccountGroupBudget(accountGroupId,limitDate),queryAccountGroupUsedAmount(accountGroupId,limitDate));
            accountGroupInfo.setLimitAmount(accountGroupAmount);
            accountGroupInfo.setUpdateTime(new Timestamp(System.currentTimeMillis()));
            currentAccountGroupAmountMap.put(accountGroupId, accountGroupInfo);
        }
    }

    /**
     * 是否核对账户组额度
     * @param accountGroupId    账户组Id
     * @param lOfficeID            办事处Id
     * @param lCurrencyID        币种id
     * @return
     * 1: 当前可用额度为-1.
     * 2: 账户组更新时间与当前应用服务器时间差是否超过一个小时.
     * 3: 开机日是否与额度日期不同.
     *
     */
    public static int isCheckAccountGroup(long accountGroupId,long lOfficeID,long lCurrencyID) throws Exception{
        int isCheckAccountGroup = 0;
        AccountGroupInfo accountGroupInfo = currentAccountGroupAmountMap.get(accountGroupId);
        if(accountGroupInfo != null){
            //如果"当前可用额度"为-1或"额度日期"不等于开机日或"更新时间"与当前应用服务器时间差值超过1个小时,则执行核对逻辑
            //a、"当前可用额度"为-1
            if(accountGroupInfo.getLimitAmount() <= 0){
                return 1;
            }
            //b、账户组更新时间与当前应用服务器时间差是否超过一个小时
            if(accountGroupInfo.getUpdateTime() != null){
                if((System.currentTimeMillis()-accountGroupInfo.getUpdateTime().getTime()) > 1*60*60*1000){
                    return 2;
                }
            }
            //c、开机日是否与额度日期不同
            Timestamp systemDate = Env.getSystemDate(lOfficeID,lCurrencyID);
            Timestamp limitDate = accountGroupInfo.getLimitDate();
            boolean isSameDate = com.iss.itreasury.util.UtilOperation.isSameDate(systemDate,limitDate);
            if(!isSameDate){
                return 3;
            }
        }else{
            //初始化账户组额度信息
            initAccountGroup(accountGroupId);
        }
        return isCheckAccountGroup;
    }

    /**
     * 初始化账户组额度信息
     * @param accountGroupId    账户组Id
     * @throws Exception
     */
    private static void initAccountGroup(long accountGroupId) throws Exception{
        AccountGroupInfo accountGroupInfo = new AccountGroupInfo();
        Timestamp systemDate = Env.getSystemDate(1,1);
        double accountGroupAmount = UtilOperation.Arith.sub(queryAccountGroupBudget(accountGroupId,systemDate),queryAccountGroupUsedAmount(accountGroupId,systemDate));
        accountGroupInfo.setAccgroupBudget(true);
        accountGroupInfo.setLock(false);
        accountGroupInfo.setLimitDate(systemDate);
        accountGroupInfo.setLimitAmount(accountGroupAmount);
        accountGroupInfo.setUpdateTime(new Timestamp(System.currentTimeMillis()));
        currentAccountGroupAmountMap.put(accountGroupId, accountGroupInfo);
    }

    /**
     * 查询账户组设置预算额度
     * @param accountGroupId    账户组Id
     * @param executedate        执行日期
     * @return
     * @throws Exception
     */
    public static double queryAccountGroupBudget(long accountGroupId,Timestamp executedate) throws Exception{
        //账户组设置预算额度
        double accountGroupBudgetAmount = 0.0;
        int year = 0;//年份
        int month = 0;//月份

        AccountGroupDao agDao = new AccountGroupDao();
        if(executedate != null){
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(executedate.getTime());
            year = calendar.get(GregorianCalendar.YEAR);
            month = calendar.get(GregorianCalendar.MONTH) + 1;
        }else{
            throw new SettlementException("执行日期为空",new Exception());
        }
        //查询账户组设置预算额度
        accountGroupBudgetAmount = agDao.queryAccountGroupBudgetAmount(accountGroupId,executedate,year,month);

        return accountGroupBudgetAmount;
    }

    /**
     * 统计查询账户组已使用额度
     * 账户组已使用额度 = 网银、CBE使用额度 + 结算、银行流水入账使用额度
     * @param accountGroupId    账户组Id
     * @param executedate        执行日期
     * @return
     * @throws Exception
     */
    public static double queryAccountGroupUsedAmount(long accountGroupId,Timestamp executedate) throws Exception{
        //账户组已使用额度
        double accountGroupUsedAmount = 0.0;
        //网银和CBE使用额度
        double ebankUsedAmount = 0.0;
        //柜台业务和入账使用额度
        double settUsedAmount = 0.0;

        AccountGroupDao agDao = new AccountGroupDao();
        //统计查询网银和CBE使用额度
        ebankUsedAmount = agDao.queryEbankUsedAmount(accountGroupId,null,executedate);
        //查询统计柜台业务和入账使用额度
        settUsedAmount = agDao.querySettUsedAmount(accountGroupId,null,executedate);

        accountGroupUsedAmount = ebankUsedAmount + settUsedAmount;
        return accountGroupUsedAmount;
    }

    /**
     * 统计查询账户组已使用额度
     * 账户组已使用额度 = 网银、CBE使用额度 + 结算、银行流水入账使用额度
     * @param accountGroupId    账户组Id
     * @param startExecuteDate    开始执行日期
     * @param startExecuteDate    结束执行日期
     * @return
     * @throws Exception
     */
    public static double queryAccountGroupUsedAmount(long accountGroupId,Timestamp startExecuteDate,Timestamp endExecuteDate) throws Exception{
        //账户组已使用额度
        double accountGroupUsedAmount = 0.0;
        //网银和CBE使用额度
        double ebankUsedAmount = 0.0;
        //柜台业务和入账使用额度
        double settUsedAmount = 0.0;

        AccountGroupDao agDao = new AccountGroupDao();
        //统计查询网银和CBE使用额度
        ebankUsedAmount = agDao.queryEbankUsedAmount(accountGroupId,startExecuteDate,endExecuteDate);
        //查询统计柜台业务和入账使用额度
        settUsedAmount = agDao.querySettUsedAmount(accountGroupId,startExecuteDate,endExecuteDate);

        accountGroupUsedAmount = ebankUsedAmount + settUsedAmount;
        return accountGroupUsedAmount;
    }
    // test
    public static void main(String[] args) {

//        accountGroup.put(1L, 2L);
//        accountGroup.put(2L, 2L);
//        accountGroup.put(3L, 2L);
//        accountGroup.put(4L, 3L);
//
//        try {
//            Thread thread1 = new Thread(){
//                public void run(){
//                    try {
////                        AccountGroupOperation accountGroupOperation = new AccountGroupOperation();
//                        System.out.println("fasdfasdfasdf1111===="+AccountGroupOperation.isOverDraftAccgroup(1, 10000, 1, 1));
//                    } catch (Exception e) {
//                        e.printStackTrace();
//                    }
//                }
//            };
//            Thread thread2 = new Thread(){
//                public void run(){
//                    try {
////                        AccountGroupOperation accountGroupOperation = new AccountGroupOperation();
//                        System.out.println("fasdfasdfasdf222===="+AccountGroupOperation.isOverDraftAccgroup(2, 10000, 1, 1));
//                    } catch (Exception e) {
//                        e.printStackTrace();
//                    }
//                }
//            };
//            Thread thread3 = new Thread(){
//                public void run(){
//                    try {
////                        AccountGroupOperation accountGroupOperation = new AccountGroupOperation();
//                        System.out.println("fasdfasdfasdf3333===="+AccountGroupOperation.isOverDraftAccgroup(3, 10000, 1, 1));
//                    } catch (Exception e) {
//                        e.printStackTrace();
//                    }
//                }
//            };
//            Thread thread4 = new Thread(){
//                public void run(){
//                    try {
////                        AccountGroupOperation accountGroupOperation = new AccountGroupOperation();
//                        System.out.println("fasdfasdfasdf44444===="+AccountGroupOperation.isOverDraftAccgroup(4, 10000, 1, 1));
//                    } catch (Exception e) {
//                        e.printStackTrace();
//                    }
//                }
//            };
//
//            thread1.start();
//            thread2.start();
//            thread3.start();
//            thread4.start();
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
    }
}
时间: 2024-10-25 11:05:56

多线程,内存存放数据检验的相关文章

Java内存存放区域与内存溢出异常(一)

**Java内存存放区域与内存溢出异常(一)** Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,这些区域都有着各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则是依赖于用户进程的启动和结束而建立和销毁,java虚拟机所管理的内存将会包括以下几个运行时数据区域,如图一. 1.在这里先介绍程序计数器 程序计数器(Program Counter Register)是一块内存较小的内存空间,它的作用可以看作是当 前线程所执行的字节码的

Java多线程内存模型

◆JMM的基本概念◆ Java作为平台无关性语言,JLS(Java语言规范)定义了一个统一的内存管理模型JMM(Java Memory Model).JMM规定了jvm内存分为主内存和工作内存 ,主内存存放程序中所有的类实例.静态数据等变量,是多个线程共享的,而工作内存存放的是该线程从主内存中拷贝过来的变量以及访问方法所取得的局部变量,是每个线程私有的其他线程不能访问.每个线程对变量的操作都是以先从主内存将其拷贝到工作内存再对其进行操作的方式进行,多个线程之间不能直接互相传递数据通信,只能通过共

代码段中存放数据

1.前面我们写的程序中,只有一个代码段,我们先来在代码段中使用数据,看看和单独一个数据段存放数据有什么差别. 考虑这样一个问题,编程计算以下8个数据的和,结果存放在ax寄存器中: 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H 我们希望循环进行累加,所以要将数据存放在一个连续内存当中,如何将这些数据存储在一组地址连续的内存单元中呢?我们可以用指令一个一个将他们送入地址连续的内存单元,可是这样又存在一个问题,到哪里去找这段内存空间? 从规范的角度讲,

struts2 ognl存放数据

ongl存放数据可以存放在对象栈(root),也可以存放在map中 一.存放在map中 1.存放在map中可以分为存放在request.session.application public String testPutDataToValueStack(){ /* * 1.往request,session,application域中存放数据 * 2.观察内存结构 */ ServletActionContext.getRequest().setAttribute("request_username&

线程系列03,多线程共享数据,多线程不共享数据

多线程编程,有时希望每个线程的数据相互隔离互不影响,有时却希望线程间能共享数据,并保持同步.本篇体验多线程共享和不共享数据. □ 多线程不共享数据 对于多线程,CLR到底是怎样为它们分配内存栈空间呢?是"一个萝卜一个坑",每个线程都有自己的栈空间:还是"大树底下好乘凉",所有的线程共享同一个栈空间? 我们让2个线程执行相同的静态方法,用到相同的变量,通过打印变量来求证多线程栈空间的分配情况. class Program { static void Main(stri

链表/堆栈(【常用方式】头节点不存放数据的方式)(C语言版)

常用的链表/堆栈 都是先 生成一个头指针head 再用头指针 申请一个 头节点空间,然后 头节点 的Data 一般是不储存数据的 , { 当用 malloc函数分配内存后head就变为了名叫head的节点了.而不在是一个单独的指针了 } { 注意只要用malloc申请的空间 才能使 指针再 下次循环 指向不同的 内存空间 ,即每次申请的内存 地址都是一定不相同的,除非free了 这个内存空间,否则不可能再次被使用  } 当为链表/堆栈 为空时 则头节点 head->Next=NULL;否则则指向

存储过程存放数据方式

存储过程存放数据的方式主要有: 1.将数据存放到文件中:select c_content into outfile 'D:\\action.properties'; 2.将数据保存到数据库中: 存储过程的功能非常强大,在某种程度上甚至可以替代业务逻辑层.

测试向内存写数据

1 //function1向指定内存写数据,已知a的地址是18FEF0 2 3 int function1() 4 { 5 int a=0; 6 int *p=&a; 7 int *q=(int*)0x18FEF0; //指定q的地址为0x18FEF0 8 9 printf("a=0的地址=%X\n",&a); 10 printf("*p的地址=%X\n",p); 11 printf("a的值=%d\n",a); 12 print

Xilinx VDMA 24位流输出与32位AXI总线的内存 流数据关系

测试方法采用了VDMA仅有MM2S通道, 内存中的图像帧是用MicroBlaze核写入的一个colorbar. VDMA的mhs部分如下, 因为我的输出用了Digilent的HDMI核,而这个HDMI核是32位的,我自己写了个axis_24_32的位宽转换的ip,这个暂且按下不表. BEGIN axi_vdma PARAMETER INSTANCE = axi_vdma_0 PARAMETER HW_VER = 5.04.a PARAMETER C_USE_FSYNC = 0 PARAMETER