首页 > 技术文章 > 一种优化操作list、数组的多线程解决方案。

sean-zeng 2019-11-12 15:01 原文

这几天接触到了一些操作list的功能,由于list太长,加上每条数据的处理时间,导致性能下降,正好利用学来的多线程知识和网上的资料结合实践一番,写出了一个通用类如下。

/**
 * 操作数组的线程
 *
 * @author 80004133
 */
public abstract class OperateListThread{
	/**
	 * 核心数组,用户需要操作的数组
	 */
	public Object[] arr;

	private static final Logger logger = LoggerFactory.getLogger(OperateListThread.class);
	/**
	 * 操作数组线程的数量,默认为5
	 */
	private int threadNum = 5;

	ExecutorService exec;

	public OperateListThread(List obj, int threadNum){
		this.arr = obj.toArray();
		this.threadNum = threadNum;
		exec = Executors.newFixedThreadPool(threadNum+1);
	}

	/**
	 * 获取操作数组后的结果
	 * <p>
	 *     有返回结果时重写该方法
	 * </p>
	 * @return
	 */
	public Object getResult(){
		return null;
	};

	/**
	 * 用户需要实现的方法
	 * <p>
	 *     代表用户希望做什么事情,该方法被run方法调用,需要用户实现
	 * </p>
	 */
	public abstract void doRun(int index);

	/**
	 * 调用此方法开始工作
	 * @throws InterruptedException
	 */
	public void doWork() throws InterruptedException {
		logger.info("Work start ------");
		long start = System.currentTimeMillis();
		int length = arr.length;
		CountDownLatch latch = new CountDownLatch(arr.length % threadNum == 0 ? threadNum : threadNum+1);
		logger.info("length:" + length + ":" + "latch:" + latch.getCount());
		for (int j = 0; j < length; j += length / threadNum) {
			MyThread m = null;
			if ((j + (length / threadNum)) <= length) {
				m = new MyThread(arr, j, j + length / threadNum, latch);
			} else {
				m = new MyThread(arr, j, length, latch);
			}
			exec.execute(m);
		}
		latch.await();
		exec.shutdown();
		logger.info("Spand time:" + (System.currentTimeMillis() - start));
		logger.info("Work end -------");
	}

	public class MyThread implements Runnable {
		Object[] arr;
		int startIndex;
		int endIndex;
		CountDownLatch latch;
 
		public MyThread(Object[] arr, int startIndex, int endIndex, CountDownLatch latch) {
			this.arr = arr;
			this.startIndex = startIndex;
			this.endIndex = endIndex;
			this.latch = latch;
		}
 
		@Override
		public void run() {
			for (int i = startIndex; i < endIndex; i++) {
				//要做的事
				doRun(i);
			}
			logger.info(Thread.currentThread().getName());
			latch.countDown();
		}
	}


	public static void main(String[] args) throws InterruptedException{
		List<Integer> arr = new ArrayList<>();
		for (int i = 1; i <= 10000; i++) {
			arr.add(i);
		}
//		int sum = 0;
//		for (int a: arr) {
//			sum += a;
//		}
//		System.out.println(sum);
		OperateListThread op = new OperateListThread(arr, 5) {
			public int sum = 0;

			public Object getResult() {
				return sum;
			}

			@Override
			public void doRun(int index) {
				sum += (int) arr[index];
			}
		};
		op.doWork();
		int result = (int)op.getResult();
		System.out.println(result);
	}
}

main方法举了一个很简单的使用实例,计算1+2+3+...+10000的和。这个通用类是一个抽象类,用法是实现这个抽象类,并只需要实现简单的doRun()方法,这个方法主要是对list做什么样的操作,index代表当前数组的位置,核心数组为arr。若你需要得到返回值,可以重写getResult()方法来获取返回值。

当然,有更好的方案或可以改正的地方欢迎联系我(QQ:2470244153),或在评论处留下您的留言。

推荐阅读