java并发--聊聊java自带的原子更新类
在多并发中,原子性是一个基本的特性,如何高效的保证原子性操作是一个比较复杂的过程,还好在java语言中,jdk提供了atomic包,在该包中定义了几类原子性更新的。本文就对这些原子更新类做个小结,至于具体源码分析可以参考之前的jdk源码系列的文章,这里不再赘述。
在jdk中,大概可以把atomic包分为以下几类:
针对特定类型的更新:
AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference,这一类的更新在更新之前就定义好了要更新的内容就是一个特定的类型,比如Boolean类型,integer类型等。对于这种类型的使用,可以说是比较简单,其使用方法基本一致,下面我们通过一个demo描述一下。
1. public class AtomicIntegerTest {
2. public static void main(String[] args) {
3. AtomicInteger integer = new AtomicInteger(0);//定义好一个整型变量
4. for (int i =0;i<100;i++){
5. new Thread(new AddTest(integer)).start();
6. }
7. }
8.
9. private static class AddTest implements Runnable{
10. private AtomicInteger data ;
11. public AddTest(AtomicInteger a) {
12. this.data = a;
13. }
14.
15. @Override
16. public void run() {
17. System.out.println(Thread.currentThread().getName()+" get data is "
18. +data.addAndGet(1));
19. }
20. }
21. }
特定类型数组的更新:
这类是更新的是一个数组结构,不像上面一样,只能更新一个。这类包括以下几个类型,AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray,当然了其使用模式也和上面的类似,我们也通过一个demo来说明一下。
1. public class AtomicIntegerArrayTest {
2. public static void main(String[] args) {
3. AtomicIntegerArray array = new AtomicIntegerArray(1);//定义一个数组
4. for (int i =0;i<100;i++){
5. new Thread(new AddTest(array)).start();
6. }
7. }
8. private static class AddTest implements Runnable{
9. private AtomicIntegerArray data ;
10. public AddTest(AtomicIntegerArray a) {
11. this.data = a;
12. }
13. @Override
14. public void run() {
15. System.out.println(Thread.currentThread().getName()+" get array[0] is "
16. +data.addAndGet(0,1));
17. }
18. }
19. }
更新某个类中的特定类型的变量:
这类是和之前的不太一样,这个类是更新某个类中的特定的元素,换句话说这个原子更新的变量是某个类中的一个成员变量。该类中的有:AtomicIntegerFieldUpdater,AtomicLongFieldUpdater,AtomicReferenceFieldUpdater
这类在使用上和之前的稍微有点不同,其定义的变量需要满足public权限,需要设置成volatile修饰,满足这两点的话,是可以使用原子整型更新器的。下面我们通过一个demo来说明一下:
1. public class AtomicIntegerFieldUpdaterTest {
2. private static final AtomicIntegerFieldUpdater<Fruit> updater = AtomicIntegerFieldUpdater.newUpdater(Fruit
3. .class,"price");//定义price是需要更新的变量
4. public static void main(String[] args) {
5. Fruit fruit = new Fruit(1,"apple");
6. for (int i =0;i<100;i++){
7. new Thread(new AddTest(fruit)).start();
8. }
9. }
10. private static class AddTest implements Runnable{
11. private Fruit f ;
12. public AddTest(Fruit f) {
13. this.f = f;
14. }
15.
16. @Override
17. public void run() {
18. System.out.println(Thread.currentThread().getName()+" get data is "
19. +updater.addAndGet(f,1));
20. }
21. }
22. private static class Fruit{
23. public volatile int price;//访问权限要public ,设置成volatile变量,以保证变量的操作可见
24. private String name;
25.
26. public Fruit(int price, String name) {
27. this.price = price;
28. this.name = name;
29. }
30.
31. public int getPrice() {
32. return price;
33. }
34.
35. public void setPrice(int price) {
36. this.price = price;
37. }
38.
39. public String getName() {
40. return name;
41. }
42.
43. public void setName(String name) {
44. this.name = name;
45. }
46. }
47. }
累加器和计数器:
累加器和计数器是为了优化之前的原子更新器而添加的,在该类别中,主要是实现累加或者其他计数功能的。该类中主要是以下几个:LongAccumulator,LongAdder,DoubleAdder,DoubleAccumulator。那么该类的使用方法我们也通过一个demo看下:
1. public class LongAccumulatorTest {
2. public static void main(String[] args) {
3. LongAccumulator longAccumulator = new LongAccumulator((x,y)->x*y,1);///自定义计算方法
4. IntStream.range(0,10).forEach(i->
5. new Thread(new AddTest(longAccumulator)).start());
6. }
7.
8. private static class AddTest implements Runnable{
9. private LongAccumulator adder;
10. public AddTest(LongAccumulator adder) {
11. this.adder = adder;
12. }
13. @Override
14. public void run() {
15. adder.accumulate(2);
16. System.out.println(Thread.currentThread().getName()+" get sum is "+adder.get());
17. }
18. }
19. }
在实际中,我们还是比较经常使用原子性操作来保证多线程下的安全,其原理的话,之前的文章介绍了主要是CAS,使用的话,也相对比较简单。