java实现并发搜索数组元素

前言:搜索是很多软件不可或缺的功能。对于有序的数组,我们可以采用常见的二分查找法,对于无序的数据,只能是挨个查找。


如果说在线程充足的情况,可以考虑使用多线程思路去解决搜索问题,即并发搜索。

思路:将原来的数组按照线程数进行分割,当有两个线程搜索元素时,可以将数组一分为二,让每个线程在指定的角标范围内搜索元素,当其中有一个线程搜索到元素则,立即将结果返回。


代码如下:


import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;


public class Demo8 {
	
	static ExecutorService pool = Executors.newCachedThreadPool();
	static final int Thread_Num = 2;
	//假设数组的值都大于或等于0,当出现小于0的情况,可以设置一个无穷小的值或新增一个标志
	static AtomicInteger result = new AtomicInteger(-1);
    public static int pSearch(int[] arr, int searchValue) throws Exception {
    	int subArrSize = arr.length / Thread_Num + 1;
    	List> re = new ArrayList>();
    	for (int i = 0, len = arr.length; i < len; i += subArrSize) {
    		//分割数组操作
			int end = i + subArrSize;
			if (end >= len) {
				end = len;
			}
			re.add(pool.submit(new SearchTask(arr, searchValue, i, end)));
		}
    	for (Future fu : re) {
    		//Future接口的get()方法具有阻塞效果,当结果还没返回时则一直阻塞,直到返回结果
			if (fu.get() > 0) return fu.get();
		}
    	return -1;
    }
    
    
    /**
     * 查询的方法
     * @param arr 指定搜索的数组
     * @param searchValue 搜索值
     * @param beginPos 开始索引
     * @param endPos 结束索引
     * @return 所在角标
     */
    public static int search(int[] arr, int searchValue, int beginPos, int endPos) {
    	int i = 0;
    	for (i = beginPos; i < endPos; i++) {
    		//当大于0所以值已经被替换,直接返回结果
    		if (result.get() > 0) {
    			return result.get();
    		}
    		if (arr[i] == searchValue) {
    			//使用CAS原理,当更新失败则说明值已经被修改过,直接返回结果
    			if (!result.compareAndSet(-1, searchValue)) {
    				return result.get();
    			}
    			return i;
    		}
		}
    	return -1;
    }
    
    /**
     * 自定义一个任务类,以便将数据封装到任务中
     */
    public static class SearchTask implements Callable {
    	int begin, end, searchValue;
    	int[] arr;
    	public SearchTask(int[] arr, int searchValue, int begin, int end) {
    		this.begin = begin;
    		this.end = end;
    		this.searchValue = searchValue;
    		this.arr = arr;
    	}
		@Override
		public Integer call() throws Exception {
			return search(arr, searchValue, begin, end);
		}
    }
}  



知识点补充:

1、CAS原理: 操作的时包含三个操作数 — 内存位置(V)、预期原值(A)和新值(B)。 如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。

2、AtomicInteger相比于是具有原子性的Integer,它的compareAndSet方法采用的是CAS原理,所以第一次会设置成功,第二次起便会失败。

3、Future模式可以异步获取接口的数据,Future.get()当数据未完成时会阻塞,直到数据获取完成,或是设置超时时间。


结尾:笔者在使用家用机做测试的时候发现,并发搜索相对于普通搜索性能上没有很大的提升,甚至更差,所以想做测试的时候,尽量选线程较多的机器,还有数组的量尽量调大,这样效果比较明显。


参考自:《实战Java高并发程序设计》

你可能感兴趣的:(java)