当两个线程操作一个列表时抛出异常,通过信号量同步
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 的详细信息,其中包含 id
和 priority
等字段。我已经根据优先级对订单列表进行了排序,并希望处理这些订单。
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;
}
试图用两个不同的线程处理 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 的详细信息,其中包含 id
和 priority
等字段。我已经根据优先级对订单列表进行了排序,并希望处理这些订单。
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;
}