当两个线程操作一个列表时抛出异常,通过信号量同步

Exception thrown when two threads manipulate a list, synchronized via semaphores

试图用两个不同的线程处理 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

我刚刚省略了订单 class 的详细信息,其中包含 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();

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

本来想更新这个忘记了。这个例子似乎显示了两个线程像你一样在信号量上交替。他们没有共享变量,但非常接近。

可能是 volatile 关键字。根据这个 article,volatile 给出了 "happens-before" 保证,但不会更多。也许试试 AtomicLong

你的问题是这样的,在获取信号量之前检查大小条件,当你获取信号量时,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;
}