问题一个个回答:fori循环肯定可以。
我觉得考官想问如下问题,并期望有如下的答案:
1.100w个对象能不能放在ArrayList中?目前主流的PC机绝对没有问题,服务器就更不要说了。
小编这里有一份Java学习资料,加我的Java学习群:985331340免费获取。以下为部分资料截图
2.使用遍历的方法来查找数据可不可以?对性能没有要求时肯定可以。
3.有没有可能使用多线程的方法来解决?显然可以,这个应该是重点。其思路是将ArrayList划分为多个片,每个线程搜索一个片,最后将结果集合起来。
4.应该使用多少个线程来跑?这个就见仁见智了,一般来说,使用CPU核心数的2倍比较好,这是个经验值。太多线程肯定不行,创建和销毁线程会大量耗费资源。
5.读取ArrayList会不会导致加锁而造成性能降低?这个不会,如果数据不是同时读写,ArrayList是没有问题的。虽然它不是一个线程安全的集合类,但是并发读取是没有问题的,它也没有读锁。
6.这种问题是否可以使用fork-join框架来完成?这个显然可以,这个问题就是典型的fork-join问题,由于fork-join框架采用了任务偷取算法,所以它会比一般的线程池要快一点点完成计算任务。
好了,废话少说,上代码:
public class ArrayList100W {
private static int LIST_LENGTH = 1000000;
//线程数量
private static int THREAD_NUMBER = 1000;
//每个线程读取的list个数
private static int SLICE_LENGTH = LIST_LENGTH/THREAD_NUMBER;
public static void main(String[] args) throws InterruptedException {
ArrayList<MyObject> myObjectArrayList = new ArrayList<>(LIST_LENGTH);
for (int i = 0; i < LIST_LENGTH; i++) {
myObjectArrayList.add(new MyObject());
}
//第一种方法,直接遍历
long start = System.currentTimeMillis();
int numberEquals2 = 0;
for (int i = 0; i < LIST_LENGTH; i++) {
if (myObjectArrayList.get(i).type == 2) {
numberEquals2 ++;
}
}
long end = System.currentTimeMillis();
System.out.println("线程数量1,线性遍历,花费的时间:"+(end-start)+" milliseconds, "+"type等于2的个数有:"+numberEquals2);
//第二种方法,用100个线程来分别跑,用来计数的变量是原子变量
start = System.currentTimeMillis();
AtomicInteger atomicNumberEquals2 = new AtomicInteger(0);
ExecutorService pool = Executors.newFixedThreadPool(THREAD_NUMBER);
for (int i = 0; i < THREAD_NUMBER; i++) {
final int threadNumber = i;
pool.execute(new Runnable() {
@Override
public void run() {
for (int j = threadNumber*SLICE_LENGTH; j < ((threadNumber+1)*SLICE_LENGTH ); j++) {
if (myObjectArrayList.get(j).type == 2) {
atomicNumberEquals2.addAndGet(1);
}
}
}
});
}
pool.shutdown();
pool.awaitTermination(1, TimeUnit.DAYS);
end = System.currentTimeMillis();
System.out.println("线程数量:"+THREAD_NUMBER+"(原子变量)花费的时间:"+(end-start)+" milliseconds, "+"type等于2的个数有:"+atomicNumberEquals2.get());
//第三种方法,用100个线程来分别跑,使用数组来计数
start = System.currentTimeMillis();
int result[] = new int[THREAD_NUMBER];
ExecutorService pool2 = Executors.newFixedThreadPool(THREAD_NUMBER);
for (int i = 0; i < THREAD_NUMBER; i++) {
final int threadNumber = i;
pool2.execute(new Runnable() {
@Override
public void run() {
for (int j = threadNumber*SLICE_LENGTH; j < ((threadNumber+1)*SLICE_LENGTH); j++) {
if (myObjectArrayList.get(j).type == 2) {
result[threadNumber]++;
}
}
}
});
}
pool2.shutdown();
pool2.awaitTermination(1, TimeUnit.DAYS);
numberEquals2 = 0;
for (int i = 0; i < THREAD_NUMBER; i++) {
numberEquals2 += result[i];
}
end = System.currentTimeMillis();
System.out.println("线程数量:"+THREAD_NUMBER+"(数组存储)花费的时间:"+(end-start)+" milliseconds, "+"type等于2的个数有:"+numberEquals2);
//第四种方法,获取本机CPU核心数*2,设置为线程数量
THREAD_NUMBER = Runtime.getRuntime().availableProcessors()*2;
SLICE_LENGTH = LIST_LENGTH/THREAD_NUMBER;
start = System.currentTimeMillis();
int[] result2 = new int[THREAD_NUMBER];
ExecutorService pool3 = Executors.newFixedThreadPool(THREAD_NUMBER);
for (int i = 0; i < THREAD_NUMBER; i++) {
final int threadNumber = i;
pool3.execute(new Runnable() {
@Override
public void run() {
for (int j = threadNumber*SLICE_LENGTH; j < ((threadNumber+1)*SLICE_LENGTH); j++) {
if (myObjectArrayList.get(j).type == 2) {
result2[threadNumber]++;
}
}
}
});
}
pool3.shutdown();
pool3.awaitTermination(1, TimeUnit.DAYS);
numberEquals2 = 0;
for (int i = 0; i < THREAD_NUMBER; i++) {
numberEquals2 += result2[i];
}
end = System.currentTimeMillis();
System.out.println("线程数量:"+THREAD_NUMBER+"(CPU核心*2)花费的时间:"+(end-start)+" milliseconds, "+"type等于2的个数有:"+numberEquals2);
}
}
class MyObject{
int type;
MyObject(){
type = new Random().nextInt(100);
}
}
我分别用线程数量10/100/1000跑了三遍,在我的pc上是这个结果:
线程1000个:
线程数量1,线性遍历,花费的时间:7 milliseconds, type等于2的个数有:9940
线程数量:1000(原子变量)花费的时间:240 milliseconds, type等于2的个数有:9940
线程数量:1000(数组存储)花费的时间:127 milliseconds, type等于2的个数有:9940
线程数量:8(CPU核心*2)花费的时间:23 milliseconds, type等于2的个数有:9940
线程100个:
线程数量1,线性遍历,花费的时间:6 milliseconds, type等于2的个数有:9884
线程数量:100(原子变量)花费的时间:56 milliseconds, type等于2的个数有:9884
线程数量:100(数组存储)花费的时间:20 milliseconds, type等于2的个数有:9884
线程数量:8(CPU核心*2)花费的时间:22 milliseconds, type等于2的个数有:9884
线程10个:
线程数量1,线性遍历,花费的时间:6 milliseconds, type等于2的个数有:9851
线程数量:10(原子变量)花费的时间:23 milliseconds, type等于2的个数有:9851
线程数量:10(数组存储)花费的时间:27 milliseconds, type等于2的个数有:9851
线程数量:8(CPU核心*2)花费的时间:24 milliseconds, type等于2的个数有:9851
结果和我想的差不多。