当两个线程通过信号灯同步列表时引发异常

时间:2019-06-21 15:25:41

标签: java multithreading semaphore

试图处理具有两个不同线程的Order对象列表,但遇到以下异常:

    Exception in thread "Thread 1" java.lang.IndexOutOfBoundsException: Index: 4, Size: 4
        at java.util.ArrayList.rangeCheck(Unknown Source)
        at java.util.ArrayList.get(Unknown Source)
        at TaskThread.run(PrintOrder_Priority.java:193)
        at java.lang.Thread.run(Unknown Source)
    Thread 1:Processing Order234,7
    Thread 2:Processing Order235,6
    Thread 1:Processing Order237,5
    Thread 2:Processing Order236,4

我刚刚省略了Order类的详细信息,其中包含诸如idpriority之类的字段。我已经根据订单的优先级对订单列表进行了排序,并希望处理订单。

class TaskThread implements Runnable 
{
    List<Order> orderList;
    static volatile int i=0;

    Semaphore sem1;
    Semaphore sem2;

    TaskThread(List<Order> orderList,Semaphore sem1,Semaphore sem2)
    {
        this.orderList=orderList;
        this.sem1=sem1;
        this.sem2=sem2;
    }

    @Override
    public void run()
    {
        for(;i<orderList.size();)
        {
            try
            {
                sem1.acquire();
                orderList.get(i).ProcessOrder();
                i++;
                sem2.release();
            } 
            catch (InterruptedException e) 
            {
                e.printStackTrace();
            }
        }
    }
}

main方法的内容:

 Semaphore sem1 = new Semaphore(1); 
 Semaphore sem2 = new Semaphore(0);
 Thread T1 = new Thread(new TaskThread(aList,sem1,sem2));
 Thread T2 = new Thread(new TaskThread(aList,sem2,sem1));
 T1.setName("Thread 1");
 T1.start();
 T2.setName("Thread 2");
 T2.start();

3 个答案:

答案 0 :(得分:1)

您的问题是,获取信号量之前要检查大小条件,当获取信号量时,i的值与您在条件中检查的值不同:

Thread1:                                 Thread2:
condition check: i ==0; OK;                condition check: i ==0; OK; 
acquire sem1:                              waiting form sem2
process i =0;                              waiting form sem2  
increase i to 1;                           waiting form sem2
release sem2;                              you acquire sem2 but  i ==1; 
condition check: i ==1; OK;                 process i =1;
waiting form sem1                          increase i to 2;  
waiting form sem1                          release sem1; 
acquire sem1 but i ==2;                     condition check: i ==2; OK;    
process i =2;                              waiting form sem2    
increase i to 3;                           waiting form sem2
release sem2;                              you acquire sem2 but  i ==3; 
condition check: i ==3; OK;                 process i =3;
waiting form sem1                          increase i to 4;  
waiting form sem1                          release sem1; 
acquire sem1 but i==4!!!!!!
you call ->> orderList.get(i) -> exception thrown

如果要使用解决方案,最简单的解决方法是在购买显示器后也添加支票

sem1.acquire();
if(i >= orderList.size()){
break;
}

答案 1 :(得分:0)

https://www.baeldung.com/java-even-odd-numbers-with-2-threads

有意更新此内容而忘记了。这个例子似乎显示了两个线程在信号量上交替变化,就像您以前那样。他们没有共享变量,但是很接近。

答案 2 :(得分:0)

可能是volatile关键字。根据此article,volatile提供了“之前发生”的保证,但没有更多。也许尝试AtomicLong