如何显示arraylist java的不同步性?
我们知道,ArrayList不是线程安全的,而VectorList是线程安全的。我想制作一个程序来显示操作是在VectorList而不是ArrayList中同步执行的。我面临的唯一问题是如何解决?什么样的手术如何显示arraylist java的不同步性?,java,arraylist,vector,thread-safety,Java,Arraylist,Vector,Thread Safety,我们知道,ArrayList不是线程安全的,而VectorList是线程安全的。我想制作一个程序来显示操作是在VectorList而不是ArrayList中同步执行的。我面临的唯一问题是如何解决?什么样的手术 例如:-如果我们向列表中的任何一个添加值,程序只需添加值。 我试图制作一个,但意识到我的程序的同步性依赖于变量j,而不是ArrayList或VectorList public class ArrayDemo implements Runnable { private static
例如:-如果我们向列表中的任何一个添加值,程序只需添加值。
我试图制作一个,但意识到我的程序的同步性依赖于变量j,而不是ArrayList或VectorList
public class ArrayDemo implements Runnable {
private static ArrayList<Integer> al = new ArrayList<Integer>();
Random random = new Random();
int j = 0;
public void run() {
while ( j < 10) {
int i = random.nextInt(10);
al.add(i);
System.out.println(i + " "+ Thread.currentThread().getName());
j++;
//System.out.println(al.remove(0));
}
}
public static void main(String[] args) {
ArrayDemo ad = new ArrayDemo();
Thread t = new Thread(ad);
Thread t1 = new Thread(ad);
t.start();t1.start();
}
}
public类ArrayDemo实现可运行{
私有静态ArrayList al=新ArrayList();
随机=新随机();
int j=0;
公开募捐{
而(j<10){
int i=随机。nextInt(10);
al.添加(i);
System.out.println(i+“”+Thread.currentThread().getName());
j++;
//系统输出println(al.remove(0));
}
}
公共静态void main(字符串[]args){
ArrayDemo ad=新的ArrayDemo();
螺纹t=新螺纹(ad);
螺纹t1=新螺纹(ad);
t、 start();t1.start();
}
}
小型测试程序:
public class Test extends Thread {
public static void main(String[] args) throws Exception {
test(new Vector<>());
test(new ArrayList<>());
test(Collections.synchronizedList(new ArrayList<>()));
test(new CopyOnWriteArrayList<>());
}
private static void test(final List<Integer> list) throws Exception {
System.gc();
long start = System.currentTimeMillis();
Thread[] threads = new Thread[10];
for (int i = 0; i < threads.length; i++)
threads[i] = new Test(list);
for (Thread thread : threads)
thread.start();
for (Thread thread : threads)
thread.join();
long end = System.currentTimeMillis();
System.out.println(list.size() + " in " + (end - start) + "ms using " + list.getClass().getSimpleName());
}
private final List<Integer> list;
Test(List<Integer> list) {
this.list = list;
}
@Override
public void run() {
try {
for (int i = 0; i < 10000; i++)
this.list.add(i);
} catch (Exception e) {
e.printStackTrace(System.out);
}
}
}
如您所见,with正常完成并返回100000
,这是在10个并行线程中添加10000个值后的预期大小
您将看到两种不同的失败:
- 在对
的调用中,有三个线程与一起死亡add()
- 即使三个失败的线程在添加任何内容之前立即死亡,其他7个线程仍应每个线程添加10000个值,总计
个值,但列表仅包含70000
个值,因此许多添加的值丢失32507
Vector
第四个测试,使用并发,也会生成正确的结果,但由于过度复制,速度要慢得多。但是,如果列表较小且很少更改,但经常读取,则它将比同步访问更快。如果需要迭代列表,这尤其好,因为如果在迭代时修改列表,即使是
Vector
和synchronizedList()
也会失败,而CopyOnWriteArrayList
将迭代列表的快照
出于好奇,我也检查了一些实现:
test(new ArrayDeque<>());
test(new ConcurrentLinkedDeque<>());
test(new LinkedBlockingDeque<>());
如您所见,unsynchronized显示了“丢失值”症状,尽管它不会因异常而失败
Exception in thread "Thread-1" java.lang.ArrayIndexOutOfBoundsException: ...
两个并行实现,以及,运行良好且快速。小型测试程序:
public class Test extends Thread {
public static void main(String[] args) throws Exception {
test(new Vector<>());
test(new ArrayList<>());
test(Collections.synchronizedList(new ArrayList<>()));
test(new CopyOnWriteArrayList<>());
}
private static void test(final List<Integer> list) throws Exception {
System.gc();
long start = System.currentTimeMillis();
Thread[] threads = new Thread[10];
for (int i = 0; i < threads.length; i++)
threads[i] = new Test(list);
for (Thread thread : threads)
thread.start();
for (Thread thread : threads)
thread.join();
long end = System.currentTimeMillis();
System.out.println(list.size() + " in " + (end - start) + "ms using " + list.getClass().getSimpleName());
}
private final List<Integer> list;
Test(List<Integer> list) {
this.list = list;
}
@Override
public void run() {
try {
for (int i = 0; i < 10000; i++)
this.list.add(i);
} catch (Exception e) {
e.printStackTrace(System.out);
}
}
}
如您所见,with正常完成并返回100000
,这是在10个并行线程中添加10000个值后的预期大小
您将看到两种不同的失败:
- 在对
的调用中,有三个线程与一起死亡add()
- 即使三个失败的线程在添加任何内容之前立即死亡,其他7个线程仍应每个线程添加10000个值,总计
个值,但列表仅包含70000
个值,因此许多添加的值丢失32507
Vector
第四个测试,使用并发,也会生成正确的结果,但由于过度复制,速度要慢得多。但是,如果列表较小且很少更改,但经常读取,则它将比同步访问更快。如果需要迭代列表,这尤其好,因为如果在迭代时修改列表,即使是
Vector
和synchronizedList()
也会失败,而CopyOnWriteArrayList
将迭代列表的快照
出于好奇,我也检查了一些实现:
test(new ArrayDeque<>());
test(new ConcurrentLinkedDeque<>());
test(new LinkedBlockingDeque<>());
如您所见,unsynchronized显示了“丢失值”症状,尽管它不会因异常而失败
Exception in thread "Thread-1" java.lang.ArrayIndexOutOfBoundsException: ...
这两个并发实现,和,工作得又好又快。即使使用简单的程序,您也可以通过进行更多的循环迭代(10次可能不够)来证明
ArrayList
不是线程安全的,并减少减慢ArrayList
上操作的其他代码,尤其是IO代码,如System.out
我通过删除Random
和System.out
调用修改了您的原始代码。我只在循环的末尾添加了一个System.out.println
,以显示可能的成功终止
但是,此代码并没有完全运行。相反,它抛出一个异常
Exception in thread "Thread-1" java.lang.ArrayIndexOutOfBoundsException: ...
从中学习的重要内容是,如果计时不正确,即使是类似的代码也可能不会遇到线程安全问题。这说明了为什么与线程相关的bug很难找到,并且在它们真正导致程序崩溃之前,它们可能潜伏在代码中很长时间
以下是修改后的代码:
import java.util.*;
public class ArrayDemo implements Runnable {
private static ArrayList<Integer> al = new ArrayList<Integer>();
int j = 0;
public void run() {
while (j < 10000) {
al.add(new Integer(1));
j++;
}
System.out.println("Array size: " + al.size());
}
public static void main(String[] args) {
ArrayDemo ad = new ArrayDemo();
Thread t = new Thread(ad);
Thread t1 = new Thread(ad);
t.start();
t1.start();
}
}
import java.util.*;
公共类ArrayDemo实现可运行{
私有静态ArrayList al=新ArrayList();
int j=0;
公开募捐{
而(j<10000){
加法(新整数(1));
j++;
}
System.out.println(“数组大小:+al.size());
}
公共静态void main(字符串[]args){
ArrayDemo ad=新的ArrayDemo();
螺纹t=新螺纹(ad);
螺纹t1=新螺纹(ad);
t、 start();
t1.start();
}
}
即使使用简单的程序,您也可以通过进行更多的循环迭代(10次可能不够)来证明ArrayList
不是线程安全的,并减少其他减慢ArrayList
上操作的代码,尤其是IO代码,如System.out
我通过删除Random
和System.out
调用修改了您的原始代码。我只在循环的末尾添加了一个System.out.println
,以显示可能的成功终止
但是,此代码并没有完全运行。相反,它抛出了一个例外