总结
①ArrayList本质是顺序表,也就是数组
②LinkedList本质是链表,双向链表。查找的时候根据大小选择一半遍历。
③所以ArrayList的get效率高。
④所以LinkedList的put效率高。
⑤CopyOnWriteArrayList线程安全。ArrayList与LinkedList线程不安全。
⑥CopyOnWriteArrayList在写的时候加锁,保证了写的时候不会copy很多副本。
引用自:https://www.cnblogs.com/dolphin0520/p/3938914.html
什么是CopyOnWrite容器
CopyOnWrite容器即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。
线程安全
ArrayList
中途报错,线程不安全。
private static ArrayList<Integer> list = new ArrayList<>();
private static ExecutorService executorService = Executors.newFixedThreadPool(20);
public static void main(String[] args){
for (int i = 0; i < 20; i++){
executorService.execute(new MyRunnable());
}
executorService.shutdown();
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
private static class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000; i++){
list.add(i);
}
System.out.println(list.size());
}
}
}
输出:
Exception in thread "pool-1-thread-3" java.lang.ArrayIndexOutOfBoundsException: 1950
at java.util.ArrayList.add(ArrayList.java:463)
at Main$MyRunnable.run(Main.java:43)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
linkedList
插入不完全,本来应该有20000个。线程不安全
public class Main{
private static List<Integer> list = new LinkedList<>();
//略
}
输出:16634
CopyOnWriteArrayList
线程安全
public class Main{
private static List<Integer> list = new CopyOnWriteArrayList<>();
//略
}
输出:20000
效率
public class Main{
private static ArrayList<Integer> arrayList = new ArrayList<>();
private static LinkedList<Integer> linkedList = new LinkedList<>();
public static void main(String[] args){
//插入
System.out.println("插入在最后面");
long s = System.currentTimeMillis();
for (int i = 0; i < 100000; i++){
arrayList.add(i);
}
System.out.println("10w次插入 arrayList:" + (System.currentTimeMillis() - s) + "ms");
long s1 = System.currentTimeMillis();
for (int i = 0; i < 100000; i++){
linkedList.add(i);
}
System.out.println("10w次插入 linkedList:" + (System.currentTimeMillis() - s1) + "ms");
//插入
System.out.println("插入在最前面");
long s2 = System.currentTimeMillis();
for (int i = 0; i < 100000; i++){
arrayList.add(0, i);
}
System.out.println("10w次插入 arrayList:" + (System.currentTimeMillis() - s2) + "ms");
long s3 = System.currentTimeMillis();
for (int i = 0; i < 100000; i++){
linkedList.add(0, i);
}
System.out.println("10w次插入 linkedList:" + (System.currentTimeMillis() - s3) + "ms");
//查找
System.out.println("查找中间");
long s4 = System.currentTimeMillis();
for (int i = 0; i < 10000; i++){
arrayList.get(50000);
}
System.out.println("10w次查找 arrayList:" + (System.currentTimeMillis() - s4) + "ms");
long s5 = System.currentTimeMillis();
for (int i = 0; i < 10000; i++){
linkedList.get(99999);
}
System.out.println("10w次查找 linkedList:" + (System.currentTimeMillis() - s5) + "ms");
}
}
输出:
插入在最后面
10w次插入 arrayList:5ms
10w次插入 linkedList:5ms
插入在最前面
10w次插入 arrayList:1994ms
10w次插入 linkedList:5ms
查找中间
10w次查找 arrayList:0ms
10w次查找 linkedList:1428ms
网友评论