Java 为多个并行流保持一个计数器的更新
试图维护一个(已同步)计数器以跟踪List.parallelStream。 代码如下:Java 为多个并行流保持一个计数器的更新,java,multithreading,atomic,Java,Multithreading,Atomic,试图维护一个(已同步)计数器以跟踪List.parallelStream。 代码如下: /** * Testing the use of AtomicInteger in List.parallelStream() */ public void UsingParallelStream() { /*Create the counter */ AtomicInteger atomicInteger = new AtomicInteger(0); /*Create an
/**
* Testing the use of AtomicInteger in List.parallelStream()
*/
public void UsingParallelStream() {
/*Create the counter */
AtomicInteger atomicInteger = new AtomicInteger(0);
/*Create and populate the list */
List<Integer> numList = new ArrayList<Integer>();
int num = 1;
for (int i = 0; i < 1000; i++) {
numList.add(num);
num ++;
}
/*Test the consistency of the counter*/
numList.parallelStream().forEach(number -> {
atomicInteger.getAndIncrement();
executeTest(atomicInteger,numList);
});
}
private void executeTest(AtomicInteger atomicInteger, List<Integer> l) {
if (atomicInteger.intValue() % 100 == 0) {
System.out.println(l.get(atomicInteger.intValue() - 1));
}
}
/**
*测试List.parallelStream()中AtomicInteger的使用
*/
使用ParallelStream()的公共void{
/*创建计数器*/
AtomicInteger AtomicInteger=新的AtomicInteger(0);
/*创建并填充列表*/
List numList=new ArrayList();
int num=1;
对于(int i=0;i<1000;i++){
numList.add(num);
num++;
}
/*测试计数器的一致性*/
numList.parallelStream().forEach(编号->{
atomicInteger.getAndIncrement();
executeTest(原子整数,numList);
});
}
私有void executeTest(AtomicInteger,列表l){
if(atomicInteger.intValue()%100==0){
System.out.println(l.get(atomicInteger.intValue()-1));
}
}
以下是结果(您可以看到计数器未同步):
100
200
300
300
401
501
501
701
800
901
800
一千
谢谢你,布莱斯,
David.executeTest(atomicInteger,numList)中的操作代码>不是原子的
if (atomicInteger.intValue() % 100 == 0) {
System.out.println(l.get(atomicInteger.intValue() - 1));
}
当发现线程atomicInteger.intValue()%100==0
为true时,尝试执行System.out.println(l.get(atomicInteger.intValue()-1))代码>,其他线程可能已更新该值
如何解决?使用局部变量:
numList.parallelStream().forEach(number -> {
int local = atomicInteger.getAndIncrement();
executeTest(local,numList);
});
private void executeTest(int local, List<Integer> l) {
if (local % 100 == 0) {
System.out.println(l.get(local - 1));
}
}
numList.parallelStream().forEach(数字->{
int local=atomicInteger.getAndIncrement();
执行测试(本地、numList);
});
私有void executeTest(int-local,列表l){
如果(本地%100==0){
System.out.println(l.get(local-1));
}
}
您需要确保每个线程在不同的值上运行。此值只能找到一次,并且只能通过getAndIncrement
的返回值找到。对原子整数的每次进一步读取操作都可能返回一个新值,该值属于另一个线程
numList.parallelStream().forEach(number -> {
var value = atomicInteger.getAndIncrement();
executeTest(value, numList);
});
private void executeTest(int value, List<Integer> l) {
if (value % 100 == 0) {
System.out.println(l.get(value - 1));
}
}
numList.parallelStream().forEach(数字->{
var value=atomicInteger.getAndIncrement();
executeTest(值,numList);
});
私有void executeTest(int值,列表l){
如果(值%100==0){
System.out.println(l.get(value-1));
}
}
首先递增,然后读取时,多个线程可能使用相同的值。原子意味着,每个操作都是原子的。这并不意味着在同一个线程中有多个操作是原子的。对不起,这是完整的代码:它仍然不是完整的代码。哪里添加了executeTest
缺少的代码。这有什么关系?请详细说明一下,如果getAndIncrement()
是原子的,这难道不意味着所有线程在任何时候都看到相同的值吗?我想我看到了一个例子:在if语句之后,thread get context switch。因此,在JVM唤醒线程之后,该值可能会有所不同,这是一个有效的示例吗?一旦我将atomicInteger传递给executeTest方法,那么它将只在本地看到,而不会在方法之外递增。请参见示例:private void executeTest(AtomicInteger计数器,列表l){if(counter.intValue()%100==0){System.out.println(l.get(counter.intValue()-1));}}}问题是操作调用了两次AtomicInteger.intValue
。下面是一个示例,thread1找到了atomicInteger.intValue
为100,并尝试打印它。同时,thread2将atomicInteger
更新为101,因此当thread1再次检索该值时,它将得到101。