交织的原因是什么?

时间:2015-02-01 22:20:37

标签: java multithreading

好的,我有两个班,Lock和Worker。

所有Lock都是创建工作者对象。现在在Worker中两个线程将运行。我创建了对象来充当锁,这样两个线程就可以同时处理两个方法中的一个,而不必等待使用共享的内部锁。所有方法都是添加到两个列表中的一个,从1到1000,所以list1和list基本上都有(或者应该)列表中有2000个数字。

我想要理解的是,如果我不使用锁,为什么在此过程中这会给我一个ArrayIndexOutOfBoundsException。我所做的只是增加一个arraylist,为什么它超出界限?如果两个线程同时读取相同大小的arraylist,arraylist是否会打开一个位置,而两个线程都试图同时放入两个数字?注意:如果我取消注释同步锁定,这很好,我只想知道幕后发生了什么。

public class Lock     {
    public static void main(String[] args)        {
        Worker x = new Worker();
        try {
            x.main();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class Worker {
    private Random random = new Random();
    private Object lock1 = new Object();
    private Object lock2 = new Object();
    private List<Integer> list1 = new ArrayList<Integer>();
    private List<Integer> list2 = new ArrayList<Integer>();

    public void main() throws InterruptedException  {
        System.out.println("Starting...");
        long start = System.currentTimeMillis();

        Thread t1 = new Thread(new Runnable() {
            public void run() {
                process();
            }
        });


        Thread t2 = new Thread(new Runnable() {
            public void run() {
                process();
            }
        });

        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch(InterruptedException e)  {
            e.printStackTrace();
        }

        long end = System.currentTimeMillis();

        System.out.println("Time take: " +(end - start) + " ms");
        System.out.println("List1: " + list1.size() +"; List2: " + list2.size());
    }

    //Without synchronized it will not fill the entire list

    public void stageOne()  {
        //synchronized (lock1)
        {
            try {
                Thread.sleep(1);
            } catch(InterruptedException e)                 {
                e.printStackTrace();
            }

            list1.add(random.nextInt(100));
        }
    }

    public void stageTwo()      {
        //synchronized (lock2)
        {
            try {
                Thread.sleep(1);
            } catch(InterruptedException e) {
                e.printStackTrace();
            }
            list2.add(random.nextInt(100));
        }
    }

    public void process(){
        for (int i = 0; i < 1000; i++)  {
            stageOne();
            stageTwo();
        }
    }
}

2 个答案:

答案 0 :(得分:1)

ArrayList不是线程安全的,没有synchronized块,两个线程都在list1list2中添加元素。

可能会发生ArrayList之一的支持数组达到其全部容量,并且在调整大小时,其中一个线程正在尝试向已经完整的数组添加元素,从而抛出异常。

答案 1 :(得分:0)

  

我想了解的是,如果我不使用锁,为什么在此过程中会给我一个ArrayIndexOutOfBoundsException

我们无法准确回答这个问题,我们只能推测。 ArrayList不是线程安全的类。这就是您需要使用同步的原因。

  

请注意,此实现未同步。如果多个线程同时访问ArrayList实例,并且至少有一个线程在结构上修改了列表,则必须在外部进行同步。

如果你不使用同步,事情就会爆发,在这种情况下,你发现它们已经发生了。

为这个特定情况推测导致此异常的原因是没有用的,因为它本质上是未定义的。 重要的是要理解,如果没有同步,每个线程相互之间的动作都没有指定的顺序。因此,无法以逻辑方式推断导致异常的事件序列。

例如,假设t1采取两项措施:

actionA();
actionB();

如果没有同步,t2完全有权查看actionB而非actionA

在某些情况下,线程交错会导致一个人尝试访问超出范围的索引。这就是为什么需要同步的原因。