java 并发编程之线性方法调用的解决方法

环境

java:1.7

前言

最近又遇到了,需要去多张表中拿数据,大概5个表;
一个表对应一个方法,线性调用的话,大概需要9秒钟。

之前我也总结过 使用CountDownLatch,但是那个没有写好,写的有点乱。

需求

我需要从6张表中拿数据;
1、先去一张表中拿到符合条件的股票代码集合
2、在用这个股票代码集合去查询另外5张表。
3、需要获取返回值

技术方案

之前我仅仅只用了CountDownLatchExecutors.newFixedThreadPool()

返回值,我是通过定义Map变量来获取的;这样做我就不得不有如下代码:

		Map<String, Map<String, Object>> stockTagData = new HashMap();
		Map<String, Object> pe = new HashMap();
		Map<String, Object> historyPe = new HashMap();
		Map<String, Object> pb = new HashMap();
		Map<String, Object> historyPb = new HashMap();

然后再设置进去。这样做代码不美观,多了的话,给人一种乱乱的感觉。


这次使用CountDownLatchExecutors.newFixedThreadPool()FutureTaskCallable来实现。

CountDownLatch 是并发的辅助方法,用来我等待的方法都执行完了。
Executors.newFixedThreadPool() 线程池。
FutureTask 用来获取方法返回的值。
Callable :有返回值就用它,无返回值就用Runnable中的run方法。

代码

类名:HitStocksThread

/**
 *
 * 
 * @version 1.0
 * @since JDK1.7
 * @author yutao
 * @company 
 * @copyright (c) 2016 SunTime Co'Ltd Inc.All rights reserved.
 * @date 2018年12月4日上午11:34:43
 */
public class HitStocksThread  implements Callable<Map<String, Map<String, Object>>> {
	
	private CountDownLatch countDownLatch;
	
	private String methodName;
	private Collection<String> stocks;
	private Date date;
	
	private Set<String> codeSet;
	
	public HitStocksThread(CountDownLatch countDownLatch, String methodName) {
		this.countDownLatch = countDownLatch;
		this.methodName = methodName;
	}

	public Collection<String> getStocks() {
		return stocks;
	}
	public void setStocks(Collection<String> stocks) {
		this.stocks = stocks;
	}
	public Date getDate() {
		return date;
	}
	public void setDate(Date date) {
		this.date = date;
	}
	public Set<String> getCodeSet() {
		return codeSet;
	}
	public void setCodeSet(Set<String> codeSet) {
		this.codeSet = codeSet;
	}
	
	/**
	 * 
	 * @see java.util.concurrent.Callable#call()
	 */
	@Override
	public Map<String, Map<String, Object>> call() throws Exception {
		
		Map<String, Map<String, Object>> result = null;
		switch (methodName) {
		case "event":
			result = TEventAllApiDao.GetStocksList(stocks, date, codeSet);
			break;
		case "nine":
			result = GgStockNineTradeStatisticsDao.getStocksColl(stocks, date, codeSet);
			break;
		case "multi":
			result = GgStockMultiSpaceStatisticsDao.getStocksColl(stocks, date, codeSet);
			break;
		case "hlht":
			result = TeventPerformanceMarkDao.getStocksColl(stocks, date, codeSet);
			break;
		case "tags":
			result = GgMystockTags1.getTagsMap(stocks);
			break;
		default:
			break;
		}
		countDownLatch.countDown();
		return result;
	}
}

这个类用于创建子线程,其根据methodName来判断,需要执行哪个方法。


类名:HitStocksTask

/**
 *
 * 
 * @version 1.0
 * @since JDK1.7
 * @author yutao
 * @company 
 * @copyright (c) 2016 SunTime Co'Ltd Inc.All rights reserved.
 * @date 2018年12月4日下午3:00:01
 */
public class HitStocksTask extends FutureTask<Map<String, Map<String, Object>>> {

	private Map<String, Map<String, Object>> result;
	private String name;
	
	/**
	 * @param callable
	 */
	public HitStocksTask(HitStocksThread callable, String name) {
		super(callable);
		this.name = name;
	}

	@Override
	protected void done() {
		super.done();
		try {
			result = this.get();
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
		}
	}

	public Map<String, Map<String, Object>> getResult() {
		return result;
	}

	public String getName() {
		return name;
	}
}

这个类继承于FutureTask,是Future的实现类。

之所以不使用Future,因为使用其get()方法时,会阻塞线程。
也就是如果在主线程中使用get()方法,就会把主线程给阻塞了。
所以使用FutureTask,在其重载的done方法中来使用get(),这样阻塞的就是子线程自己。


类名: HitStocksService

具体的应用:

/**
	 * @return
	 * @author yutao
	 * @param rows 
	 * @param page 
	 * @date 2018年12月3日上午11:26:02
	 */
	public static List<Map<String, Object>> GetHitStocksList(int page, int rows, String clientIp) {
		//获取近三个交易日的数据
		List<Date> dateList = GGDate.getLastExchangeDatas(DateUtil.getYesterday(), 3);
		
		//获取评分大于等于50分的股票代码
		Set<String> stocks = TApiStockScoreNewDao.getStocksScoreColl(dateList.get(0));
		
		Date date = dateList.get(dateList.size()-1);
		
		Set<String> codeSet = new HashSet<>();
		//初始化  需要执行的方法
		List<String> initMethodName = initMethodName();
		int size = initMethodName.size();
		//==========================================
		CountDownLatch countDownLatch = new CountDownLatch(size);
		Map<String, Map<String, Object>> tagsMap = null;
		List<HitStocksTask> futureList = new ArrayList<>();
		for(int i=0; i<size; i++) {
			String name = initMethodName.get(i);
			HitStocksThread hitStocksThread = new HitStocksThread(countDownLatch, name);
			hitStocksThread.setCodeSet(codeSet);
			hitStocksThread.setDate(date);
			hitStocksThread.setStocks(stocks);
			HitStocksTask futureTask = new HitStocksTask(hitStocksThread, name);
			ExectorThreadPool.newFixedThreadPool.submit(futureTask);
			futureList.add(futureTask);
		}
		
		result = new ArrayList<>();
		try {
			countDownLatch.await(5000, TimeUnit.MILLISECONDS);
			//下面回到主线程去获取子线程执行的结果
			for(HitStocksTask future : futureList) {
				Map<String, Map<String, Object>> reMap = future.getResult();
				if(reMap != null) {
					Collection<Map<String,Object>> values = reMap.values();
					String name = future.getName();
					if("tags".equals(name)) {
						tagsMap = reMap;
						continue;
					}
					if(values != null && !values.isEmpty()) {
						result.addAll(values);
					}
				}
			}
			Map<String, String> apiParams = new HashMap<String, String>();
			String codekey = StkPoolCacheUtil.cacheStockPool(new ArrayList<String>(codeSet));
			apiParams.put("con_key", codekey);
			apiParams.put("get_fields", "quantity_ratio;price_change_rate;name;price");
		    Map<String, Object> plateHqs = GoGoalApi.getMap(ApiCenter.V1_FT_HQ_SNAPSHOT_GET_MAP, apiParams, clientIp);
			GGLogger.warn("---GetHitStocksList--hangqing--" + plateHqs);
			for(Map<String, Object> mm : result) {
				String codeStr = mm.get("stock_code").toString();
				if(tagsMap != null) {
					Map<String, Object> tagMM = tagsMap.get(codeStr);
					if(tagMM != null) {
						mm.putAll(tagMM);
					}
				}
				String fullcode = HQBaseService.convertFullCode(codeStr);
				if(plateHqs == null) {
					continue;
				}
				Map<String, Object> map = (Map<String, Object>)plateHqs.get(fullcode);
				if(map == null) {
					continue;
				}
				//量比
				mm.put("quantity_ratio", map.get("quantity_ratio"));
				mm.put("price", map.get("price"));
				mm.put("price_change_rate", map.get("price_change_rate"));
			}
			
			ListSortPageUtils.resultOrder(result, "quantity_ratio", -1);
			result = ListSortPageUtils.limit(result, 1, 30);
			GGCacheHelper.setex(null, result, 60*5, "aihit", params);
			result = ListSortPageUtils.limit(result, page, rows);
			
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * 
	 * @author yutao
	 * @return 
	 * @date 2018年12月4日上午11:54:26
	 */
	private static List<String> initMethodName() {
		List<String> name = new ArrayList<String>() {
			{
				add("event");
				add("nine");
				add("multi");
				add("hlht");
				add("tags");
			}
		};
		return name;
	}

上面这个类 是程序的入口,当然我是从项目里抽出来的,所以没有main方法。

总结

1、当并发编程的方法需要有返回结果时,实现Callable<>接口;
2、获取子线程的结果,可以继承FutureTask<>,再重写done方法。
3、CountDownLatch 我这里用于主线程去等待子线程执行完毕。
4、上面的写法应该类似于策略模式。

我上面的方法,里面很多都是公司自己封装的方法。请根据情况自己删除。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山鬼谣me

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值