小编给大家分享一下Java中常用的原子类有哪些,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!
Java中提供了一些原子类,原子类包装了一个变量,并且提供了一系列对变量进行原子性操作的方法。我们在多线程环境下对这些原子类进行操作时,不需要加锁,大大简化了并发编程的开发。
目前Java中提供的原子类大部分底层使用了CAS锁(CompareAndSet自旋锁),如AtomicInteger、AtomicLong等;也有使用了分段锁+CAS锁的原子类,如LongAdder等。
AtomicInteger与AtomicLong的底层实现与用法基本相同,不同点在于AtomicInteger包装了一个Integer型变量,而AtomicLong包装了一个Long型变量。
AtomicInteger与AtomicLong的底层实现都使用了CAS锁。
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
/**
* @author IT00ZYQ
* @date 2021/5/24 15:33
**/
public class T13_AtomicInteger {
private static AtomicInteger atomicInteger = new AtomicInteger();
private static AtomicLong atomicLong = new AtomicLong();
private static Integer integer = 0;
private static Long lon = 0L;
public static void main(String[] args) {
// 创建10个线程,分别对atomicInteger、atomicLong、integer、lon进行1000次增加1的操作
// 如果操作是原子性的,那么正确结果 = 10 * 1000 = 10000
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(() -> {
for (int j = 1; j <= 1000; j++) {
atomicInteger.incrementAndGet();
atomicLong.incrementAndGet();
integer ++;
lon ++;
}
});
}
// 启动线程
for (Thread thread : threads) {
thread.start();
}
// 保证10个线程运行完成
try {
for (Thread thread : threads) {
thread.join();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("AtomicInteger的结果:" + atomicInteger);
System.out.println("AtomicLong的结果:" + atomicLong);
System.out.println("Integer的结果:" + integer);
System.out.println("Long的结果:" + lon);
}
}
运行结果:
AtomicInteger的结果:10000
AtomicLong的结果:10000
Integer的结果:4880
Long的结果:4350
Process finished with exit code 0
多次运行发现原子类AtomicInteger与AtomicLong每次都能得到正确的结果10000,但是非原子类Integer与Long一般情况下都达不到10000,每次的结果也可能不一样。
LongAdder的底层实现使用了分段锁,每个段使用的锁是CAS锁,所以LongAdder的底层实现是分段锁+CAS锁。
在上面的程序添加了一个LongAdder变量进行测试
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
/**
* @author IT00ZYQ
* @date 2021/5/24 15:33
**/
public class T13_AtomicInteger {
private static AtomicInteger atomicInteger = new AtomicInteger();
private static AtomicLong atomicLong = new AtomicLong();
private static LongAdder longAdder = new LongAdder();
private static Integer integer = 0;
private static Long lon = 0L;
public static void main(String[] args) {
// 创建10个线程,分别对atomicInteger、atomicLong、integer、lon进行1000次增加1的操作
// 如果操作是原子性的,那么正确结果 = 10 * 1000 = 10000
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(() -> {
for (int j = 1; j <= 1000; j++) {
atomicInteger.incrementAndGet();
atomicLong.incrementAndGet();
integer ++;
lon ++;
longAdder.increment();
}
});
}
// 启动线程
for (Thread thread : threads) {
thread.start();
}
// 保证10个线程运行完成
try {
for (Thread thread : threads) {
thread.join();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("AtomicInteger的结果:" + atomicInteger);
System.out.println("AtomicLong的结果:" + atomicLong);
System.out.println("Integer的结果:" + integer);
System.out.println("Long的结果:" + lon);
System.out.println("LongAdder的结果:" + longAdder);
}
}
运行结果:
AtomicInteger的结果:10000
AtomicLong的结果:10000
Integer的结果:6871
Long的结果:6518
LongAdder的结果:10000
Process finished with exit code 0
LongAdder类也是能够正确输出结果的。
package juc;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
/**
* @author IT00ZYQ
* @date 2021/5/24 15:51
**/
public class T14_AtomicClassPerformance {
private static AtomicLong atomicLong = new AtomicLong();
private static LongAdder longAdder = new LongAdder();
/**
* 线程数
*/
private static final int THREAD_COUNT = 100;
/**
* 每次线程循环操作次数
*/
private static final int OPERATION_COUNT = 10000;
public static void main(String[] args) {
Thread[] threads = new Thread[THREAD_COUNT];
// 创建对AtomicLong进行操作的线程
for (int i = 0; i < THREAD_COUNT; i++) {
threads[i] = new Thread(() -> {
for (int j = 0; j < OPERATION_COUNT; j++) {
atomicLong.incrementAndGet();
}
});
}
long start1 = System.currentTimeMillis();
// 启动线程
for (Thread thread : threads) {
thread.start();
}
// 保证线程运行完成
try {
for (Thread thread : threads) {
thread.join();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
long end1 = System.currentTimeMillis();
// 创建对LongAdder进行操作的线程
for (int i = 0; i < THREAD_COUNT; i++) {
threads[i] = new Thread(() -> {
for (int j = 0; j < OPERATION_COUNT; j++) {
longAdder.increment();
}
});
}
long start2 = System.currentTimeMillis();
// 启动线程
for (Thread thread : threads) {
thread.start();
}
// 保证线程运行完成
try {
for (Thread thread : threads) {
thread.join();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
long end2 = System.currentTimeMillis();
System.out.println("AtomicLong运行时间: " + (end1 - start1) + "ms, 运行结果:" + atomicLong);
System.out.println("LongAdder运行时间: " + (end2 - start2) + "ms, 运行结果:" + longAdder);
}
}
THREAD_COUNT = 100, OPERATION_COUNT = 1000
时的运行结果
AtomicLong运行时间: 40ms, 运行结果:100000
LongAdder运行时间: 57ms, 运行结果:100000
Process finished with exit code 0
THREAD_COUNT = 100, OPERATION_COUNT = 10000
时的运行结果
AtomicLong运行时间: 108ms, 运行结果:1000000
LongAdder运行时间: 85ms, 运行结果:1000000
Process finished with exit code 0
THREAD_COUNT = 100, OPERATION_COUNT = 1000000
时的运行结果
AtomicLong运行时间: 6909ms, 运行结果:100000000
LongAdder运行时间: 468ms, 运行结果:100000000
Process finished with exit code 0
THREAD_COUNT = 10, OPERATION_COUNT = 1000000
时的运行结果
AtomicLong运行时间: 788ms, 运行结果:10000000
LongAdder运行时间: 162ms, 运行结果10000000
Process finished with exit code 0
当THREAD_COUNT * OPERATION_COUN
足够小时,AtomicInteger的性能会略高于LongAdder,而随着THREAD_COUNT * OPERATION_COUN
的增加,LongAdder的性能更高,THREAD_COUNT * OPERATION_COUN
足够大时,LongAdder的性能远高于AtomicInteger。
AtomicLong的原子性自增操作,是通过CAS实现的。在竞争线程数较少且每个线程的运行所需时间较短的情况下,这样做是合适的。但是如果线程竞争激烈,会造成大量线程在原地打转、不停尝试去修改值,但是老是发现值被修改了,于是继续自旋。 这样浪费了大量的CPU资源。
LongAdder在竞争激烈时,多个线程并不会一直自旋来修改值,而是采用了分段的思想,各个线程会分散累加到自己所对应的Cell[]数组的某一个数组对象元素中,而不会大家共用一个,把不同线程对应到不同的Cell中进行修改,降低了对临界资源的竞争。本质上,是用空间换时间。
Java主要应用于:1. web开发;2. Android开发;3. 客户端开发;4. 网页开发;5. 企业级应用开发;6. Java大数据开发;7.游戏开发等。
看完了这篇文章,相信你对“Java中常用的原子类有哪些”有了一定的了解,如果想了解更多相关知识,欢迎关注亿速云行业资讯频道,感谢各位的阅读!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。