AtomicInteger属于Atomic Variables族。 主要好处是使用它不会阻塞而不是进行阻塞同步,因此避免了线程的挂起和重新调度。
AtomicInteger基于“比较和交换”机制,并且是原子变量的标量组的一部分。
我们的第一个用例是可以多次访问的网页上的功能。
package com.gkatzioura.concurrency; import java.util.concurrent.atomic.AtomicInteger; public class AtomicIntegerExample {
private AtomicInteger atomicInteger = new AtomicInteger();
public void serveRequest() {
atomicInteger.incrementAndGet();
/**
* logic
*/
}
public int requestsServed() {
return atomicInteger.get();
} }
并测试我们的用例
package com.gkatzioura.concurrency; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class AtomicIntegerExampleTest {
private AtomicIntegerExample atomicIntegerExample;
@BeforeEach
void setUp() {
atomicIntegerExample = new AtomicIntegerExample();
}
@Test
void testConcurrentIncrementAndGet() throws ExecutionException, InterruptedException {
final int threads = 10 ;
ExecutorService executorService = Executors.newFixedThreadPool(threads);
List<Future> futures = new ArrayList();
for ( int i = 0 ; i {
atomicIntegerExample.serveRequest();
return null ;
}));
}
for (Future future: futures) {
future.get();
}
Assertions.assertEquals( 10 ,atomicIntegerExample.requestsServed());
} }
除了使用原子整数作为计数器之外,您还可以在各种情况下使用它。 例如线程安全的循环算法。
package com.gkatzioura.concurrency; import java.util.concurrent.atomic.AtomicInteger; public class AtomicIntegerRoundRobin {
private final int totalIndexes;
private final AtomicInteger atomicInteger = new AtomicInteger(- 1 );
public AtomicIntegerRoundRobin( int totalIndexes) {
this .totalIndexes = totalIndexes;
}
public int index() {
int currentIndex;
int nextIndex;
do {
currentIndex = atomicInteger.get();
nextIndex = currentIndex< Integer.MAX_VALUE ? currentIndex+ nextIndex = currentIndex< Integer.MAX_VALUE ? currentIndex+ 1 : 0 ;
} while (!atomicInteger.compareAndSet(currentIndex, nextIndex));
return nextIndex % totalIndexes;
} }
totalIndex是索引的总数。 当请求下一个索引的请求时,计数器将增加,并进行比较和设置操作。 如果由于另一个线程而失败,则它将再次尝试该操作,并将获得计数器的下一个值。
模运算将给出当前索引。 如果原子整数达到最大值,则应将其重置为零。 重置会导致边缘情况并更改索引的顺序。 如果这是一个问题,则可以根据总索引大小来调整最大值以避免这种情况。
还对此进行了一些测试。
package com.gkatzioura.concurrency; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; AtomicIntegerRoundRobinTest { class AtomicIntegerRoundRobinTest {
private static final int MAX_INDEX = 10 ;
private AtomicIntegerRoundRobin atomicIntegerRoundRobin;
@BeforeEach
void setUp() {
atomicIntegerRoundRobin = new AtomicIntegerRoundRobin(MAX_INDEX);
}
@Test
void testIndexesSerially() {
for ( long i= 0 ;i<MAX_INDEX* 20 ;i++) {
System.out.println(atomicIntegerRoundRobin.index());
}
Assertions.assertEquals( 0 , atomicIntegerRoundRobin.index());
}
@Test
void testIndexesConcurrently() throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool( 4 );
List<Future> futures = new ArrayList();
for ( int i = 0 ; i atomicIntegerRoundRobin.index()));
}
for (Future future: futures) {
System.out.println(future.get());
}
Assertions.assertEquals( 0 ,atomicIntegerRoundRobin.index());
} }
翻译自: https://www.javacodegeeks.com/2019/11/atomicinteger-on-java-and-round-robin.html