多线程应用及问题:主线程阻塞,次级线程内包含的runnable查询类型方法的执行而终止当前代码块,导致同步锁无法释放

业务:快速处理大量数据,保证数据安全的情况下,提高数据处理速度

技术: 使用ConcurrentHashMap和ThreadPoolExecutor、CountDownLatch实现多线程

一、按数据量创建对应数目的线程

	public void userThreadPool(String[] infor, Ggtable gg,
			Map<String, Map<String, List<ClickCountShow>>> result,
			Map<String, List<ClickCountShow>> value, String modelname)
			throws InterruptedException {
		// 每个线程处理的数组大小
		int threadSize = 5;
		int dataSize = infor.length;
		int RunnNum = dataSize / threadSize + 1;
		ThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(RunnNum);
		CountDownLatch countdownlatch = new CountDownLatch(RunnNum);
		String[] newinfor = null;
		for (int i = 0; i < RunnNum; i++) {
			if ((i + 1) == RunnNum) {
				newinfor = Arrays.copyOfRange(infor, threadSize * i, dataSize);
			} else {
				newinfor = Arrays.copyOfRange(infor, i * threadSize, threadSize
						* (i + 1));
			}
			ExecutorSt stRunnable = new ExecutorSt(newinfor, countdownlatch,
					gg, result, value, modelname);
			executor.execute(stRunnable);
		}
		countdownlatch.await();
		executor.shutdown();
	}

次级业务类将数据分类存储到ConcurrentHashMap中:

public class ExecutorSt implements Runnable {
		boolean flag = true;
		private CountDownLatch countdownlatch;
		private String[] infor;
		private Map<String, Map<String, List<ClickCountShow>>> result;
		private Map<String, List<ClickCountShow>> value = null;
		private Ggtable gg;
		private String modelname;

		public ExecutorSt(String[] infor, CountDownLatch countdownlatch,
				Ggtable gg,
				Map<String, Map<String, List<ClickCountShow>>> result,
				Map<String, List<ClickCountShow>> value, String modelname) {
			this.infor = infor;
			this.countdownlatch = countdownlatch;
			this.gg = gg;
			this.result = result;
			this.modelname = modelname;
			this.value = value;
		}

		@Override
		public void run() {
			if (infor != null && infor.length > 0) {
				delinfor();
			}
			countdownlatch.countDown();
		}

		public void delinfor() {
			for (String str : infor) {
				// 赋值userid@时间@ip@MacAddress
				String[] info = str.split("@");
				GetOrgInfor gi=new GetOrgInfor(Integer.valueOf(info[0]));
				FutureTask<Object[]>obj=new FutureTask<>(gi);
				new Thread(obj).start();
				if (obj != null) {
					try {
							Object[] rs=obj.get();
							String key =(String) rs[1];
							String key2 =(String) rs[0];
							ClickCountShow ccs = new ClickCountShow(
									modelname, gg.getGgtitle(),
									new Integer(info[0]), key2, key,
									info[1], info[2], info[3]);
							List<ClickCountShow> listccs = null;
							// 存放组织名对应的map
							if (result.containsKey(key) == false) {
								// 创建新的map存储map<username,list>
								value = new ConcurrentHashMap<String, List<ClickCountShow>>();
								listccs = new ArrayList<>();
								listccs.add(ccs);
								value.put(key2, listccs);
								result.put(key, value);
							} else {
								value = result.get(key);
								if (value.containsKey(key2) == false) {
									// 不存在则新增数据
									listccs = new ArrayList<>();
									listccs.add(ccs);
									value.put(key2, listccs);
								} else {
									listccs = value.get(key2);
									listccs.add(ccs);
								}
							}
					} catch (NumberFormatException e) {
						// TODO Auto-generated catch block
						//e.printStackTrace();
					} catch (Exception e) {
						// TODO Auto-generated catch block
						//e.printStackTrace();
						System.out.println("数据存在错误!");
					}
				}
			}
		
		}
	}

次级线程中创建新的Callable类型的GetOrgInfor线程来实现查询,避免查询逻辑导致当前线程停止,主线程阻塞

    public class GetOrgfInfor implements Callable<Object[]>{
    	private Integer userid; 
    	public GetOrgfInfor(Integer userid){
    		this.userid=userid;
    	}
		@Override
		public Object[] call() throws Exception {
			return iuserinfoservice.getOrgnameByUserId(Integer.valueOf(userid));
		}
    	
    }

主线程声明result等对象,并调用线程池创建次级线程

public String getInfo() {
		ClickCount cc = iclickcountservice.getClickCountByGgtableId(ggtableId);
		// 创建存储的map集合
		// <orgname,map<username,List>>
		Map<String, Map<String, List<ClickCountShow>>> result = new ConcurrentHashMap<>();
		Map<String, List<ClickCountShow>> value = null;
		ModelBasic model = imodelbasicservice.getTypeById(cc.getModelid());
		Ggtable gg = itongyongservice.findByID(ggtableId);
		String modelname = model.getModelname();
		if (cc.getUsercount() != null) {
			String[] allclick = cc.getUsercount().split("#");
			try {
				userThreadPool(allclick, gg, result, value, modelname);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}

		request.setAttribute("result", result);
		return "singleclickshow";

	}

其他:

 问题:ssh框架应用多线程,若当前逻辑需要创建新线程去后台查询,且该查询则其他重复查询单线程对后台请求如果该请求为runnable无返回,则当前线程直接停止,线程跳转停止进入。主线程中的次级线程会因为次级线程内包含的runnable查询类型方法的执行而终止当前代码块,导致同步锁无法释放,主线程进入阻塞态。

  解决办法:使用合并查询来减少次级线程中包含的runnable类型查询,且将查询方法包含在新的CallAable线程中,从result中获取查询的内容,用于次级线程处理合并concurrentHashMap

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值