常用的多线程使用方式总结

总论

1.可以不用多线程最好不要用

2.如果可以不共享数据最好不要共享

3.服务器端最佳线程数量=((线程等待时间+线程cpu时间)/线程cpu时间) * cpu数量

因为数据库访问等待造成线程等待时间长比较长见,下面的例子就是以数据库数据迁徙程序说明。

常用模式

1.分几个线程处理不同数据

适用场景:数据可以容易的分开处理

		int dbMax = 10;
		int tableMax = 16;
		ExecutorService executorService = Executors.newFixedThreadPool(40);
		latch = new CountDownLatch(dbMax * tableMax);
		for (int tableNo = 1; tableNo <= tableMax; tableNo++) {
			for (int dbNo = 1; dbNo <= dbMax; dbNo++) {
				// 启动线程
				executorService.execute(new UserinfoRunable(dbNo, tableNo));

			}
		}
		executorService.shutdown();
		try {
			latch.await();
		} catch (InterruptedException e1) {
			log.error("threadLatch.await()", e1);
		}
		log.info("main End");

 下类省去了部分代码

	static class UserinfoRunable implements Runnable {
		int dbNo;
		int tableNo;

		public UserinfoRunable(int dbNo, int tableNo) {
			this.dbNo = dbNo;
			this.tableNo = tableNo;
		}

		@Override
		public void run() {
			while (opSize == bantchSize) {
				log.debug("db-table:" + dbNo + "-" + tableNo + " dealSize:" + dealNum);
				//省去代码
			}                    
			latch.countDown();
		}
}

 

2.线程协作来处理同一批数据

适用场景:数据处理是一个类似生产线情况,每个生产过程费时不同

数据操作方法

package com.jd.sns.dc.common;

import java.util.Collection;
import java.util.concurrent.BlockingQueue;

/**
 * 阻塞队列
 * @author guanpanpan
 *
 */
public class BlockingQueueUtil {
	/**
	 * 向队列加入一组数据,如果对队已满会阻塞
	 */
	public static <T> void add(BlockingQueue<T> blockingQueue, Collection<T> collection) throws InterruptedException {
		for (T object : collection) {
			blockingQueue.put(object);
		}
	}

	/**
	 * 向队列加入单个数据,如果对队已满会阻塞
	 */
	public static <T> void add(BlockingQueue<T> blockingQueue, T object) throws InterruptedException {
		blockingQueue.put(object);
	}
}

 

BlockingQueue<ChangeLogBantch> idBantchQueue = new LinkedBlockingQueue<ChangeLogBantch>(1000);

 

 

 取数据

while (run) {
				try {
					List<ChangeLog> changeLogs = changeLogDao.getChangeLogs1(dbNo, checkStartId, checkIdBantchCount);
					List<ChangeLogBantch> idBantchBeans = ChangeLogBantch.createIdBantchBeanList(dbNo, DcConst.BANTCH_COUNT,
							changeLogs, true);
					// 当取出的数据不满批查询数量的时候,认为这次的增量校验完成
					if (changeLogs.size() < checkIdBantchCount) {
						run = false;
					}
					// 更新最大ID
					if (idBantchBeans.size() > 0) {
						// 遍历,获得这次取出的最大的ID,作为下次查询的参数
						checkStartId = changeLogs.get(changeLogs.size() - 1).getChangeLogId();
						log.debug("idGeter:" + idBantchBeans);
						dataGeter.addIdBantchAll(idBantchBeans);
					}
				} catch (Exception ex) {
					log.error("Error in read db!", ex);
				}
			}
			IdGeter.idGeterLatch.countDown();

 

 消费数据

	/**
	 * 获取一个IDBantchBean 非阻塞式调用,返回null表示已拿完
	 */
	public ChangeLogBantch getIdBantch() {
		return idBantchQueue.poll();
	}

 

		public void run() {
			log.debug("get CompareBeans start" + ThreadUtil.getLogName());
			while (run) {
				ChangeLogBantch idBantch = getIdBantch();
				if (idBantch == null) {
					if (!ID_GETER_RUN) {
						run = false;
					}
				} else {
					try {
						List<CompareBean> compareBeans = checkService.getCompareBeans(idBantch);
						dataCompareter.addCompareBean(compareBeans);
						log.debug("CompareBeans:" + ThreadUtil.getLogName() + compareBeans);
						// 两边都为空的数据记录日志
						CkDataGeter.notInChangeLogIds.addAll(checkService.getNotInChangeLogIds(idBantch, compareBeans));
					} catch (SQLException e) {
						log.error("Get data from db error!", e);
						// 出错后将这批ID放回队列中
						addIdBantch(idBantch);
					}
				}
			}
			log.debug("get CompareBeans end" + ThreadUtil.getLogName());
			CkDataGeter.dataGeterLatch.countDown();
		}

 附一:使用取模来实现多线程处理不同数据

	@Override
	public long getMode(String pin, int modeSize) {
		return getHash(pin) % modeSize + 1;
	}

 

			if (modeNo != routeUtil.getMode(pin, modeSize)) {
				continue;
			}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值