java并发编程-12个原子类
背景
多线程更新变量的值,可能得不到预期的值,当然增加syncronized关键字可以解决线程并发的问题。
这里提供另外一种解决问题的方案,即位于 java.util.concurrent.atomic包下的原子操作类,提供了一种用法简单,性能高效,线程安全的更新变量的方式。
其它两个附带的类顺带看了一下:
longaddr 多线程先的sum操作
longaccomulator 多线程下的函数式操作,性能低于atomiclong,主要是函数式的支持;
简单分类:
基本类型原子类
使用原子的方式更新基本类型,包括:
- atomicboolean
- atomicinteger
- atomiclong
核心方法:
直接看源码了。
类签名:
public class atomicinteger extends number implements java.io.serializable {}
方法 | 功能说明 |
---|---|
构造方法 | 两个构造方法,不传或者传入值 |
get方法 | get()获取值;对应的有set(int)方法,layzyset(int) 懒设置 |
getandadd(int) | 获得老值然后增加一个数字, 对应的有addandget(int)增加一个数字并返回新值 |
getandset(int) | 获得老值然后更新为新值 |
getandincreament() | 获得老值然后+1,对应的有increamentandget() +1然后返回新值 |
getanddecrement() | 获得老值然后-1 ,对应的有decrementandget() -1然后返回新值 |
getandupdate(intunaryoperator) | 获取老值然后执行一个函数得到新值并设置,对应的有updateandget(intunaryoperator) 先执行内置函数式接口再返回新值 |
getandaccumulate(int,intbinaryoperator) | 获取老值,然后把老值和第一个参数进行函数运算的返回值并设置 ,对应的有accumulateandget(int,intbinaryoperator) 执行运算然后返回新值 |
compareandset(int,int) | 对比如果跟预期值相等则设置为新值,对应的有weakcompareandset(int,int)这个是不保证顺序设置 |
tostring | 返回数字的字符串形式 |
number继承过来的方法 | longvalue(),bytevalue()直接做了类型转换 |
object继承过来的方法 | 直接沿用object的方法 |
底层是基于 unsafe来实现,基于cas来原子性;
来研究一下unsafe的实现源码:
/** * atomically decrements by one the current value. * * @return the previous value */ public final int getanddecrement() { return unsafe.getandaddint(this, valueoffset, -1); }
public final int getandaddint(object var1, long var2, int var4) { int var5; do { var5 = this.getintvolatile(var1, var2); } while(!this.compareandswapint(var1, var2, var5, var5 + var4)); return var5; }
大致的处理流程是:死循环,对比; 也就是cas;
利用了volatile的特性,多线程的变量可见性;
原子数组
通过原子的方式更新数组中的某个元素;
包含3个类:
- atomicintegerarray
- atomicintegerlongarray
- atomicreferencearray
抓一个类来分析研究一下:
public class atomicintegerarray implements java.io.serializable {}
方法 | 说明 |
---|---|
构造方法 | public atomicintegerarray(int length),public atomicintegerarray(int[] array)这里会做一个clone,不影响传入的数组的值 |
length | 得到内部数组的长度 |
get,set,layziset | 获取,设置,懒设置 |
compareandset,weakcompareandset | cas操作, weak方法不保证操作的顺序性 |
getandadd,getandupdate,getandaccumulate | 有反向的方法,就是先计算,然后返回新值 |
tostring | 打印出数组【数字1,数字2】 |
原子类型的操作比较特殊一点:
/** * atomically adds the given value to the element at index {@code i}. * * @param i the index * @param delta the value to add * @return the previous value */ public final int getandadd(int i, int delta) { return unsafe.getandaddint(array, checkedbyteoffset(i), delta); }
private long checkedbyteoffset(int i) { if (i < 0 || i >= array.length) throw new indexoutofboundsexception("index " + i); return byteoffset(i); } private static long byteoffset(int i) { return ((long) i << shift) + base; }
这块获取数组中的值时候用到了一个移位操作;
更新引用
原子更新类atomicinterger只能更新一个变量,如果要更新多个不同的变量就要用到原子更新引用 类型提供的类;
- atomicreference 更新引用类型
- atomicreferencefieldupdater 更新引用类型的字段
- atomicmarkablererence 更新带有标志位的引用类型
以atomicreference为例子:
签名:public class atomicreference
方法: 底层分析: 利用了unsafe提供的特性保证了原子操作; 需要原子的更新某个类的某个字段,需要用到原子更新字段类; 使用要点: 原子操作类都介绍了一下,适当的场景的话,简单的说一下我使用过的两个场景: 原创不易,转载请注明出处。
方法
说明
构造方法
public atomicreference(v initialvalue) 带初始值;public atomicreference()
get,set,lazyset
设置,获取,懒设置
compareandset,weakcompareandset
cas操作,weak方法不保证顺序
getandset,getandupdate,getandaccumulate
有反向的操作
tostring
打印出里面的对象
/**
* atomically sets to the given value and returns the old value.
*
* @param newvalue the new value
* @return the previous value
*/
@suppresswarnings("unchecked")
public final v getandset(v newvalue) {
return (v)unsafe.getandsetobject(this, valueoffset, newvalue);
}
原子更新字段
package com.cocurrenttest.atomictest;
import lombok.allargsconstructor;
import lombok.builder;
import lombok.data;
import lombok.noargsconstructor;
/**
* 说明:人实体
* @author carter
* 创建时间: 2019年12月06日 19:27
**/
@data
@noargsconstructor
@allargsconstructor
@builder
public class person {
private string name;
//注意,只能是int,integer会报错哦
public volatile int age;
}
package com.cocurrenttest.atomictest;
import java.util.concurrent.atomic.atomicintegerfieldupdater;
/**
* 说明:todo
* @author carter
* 创建时间: 2019年12月06日 19:26
**/
public class testatomicintegerupdater {
public static void main(string[] args) {
final atomicintegerfieldupdater<person> personatomicintegerfieldupdater = atomicintegerfieldupdater.newupdater(person.class, "age");
person person = person.builder().name("lifuchun").age(30).build();
personatomicintegerfieldupdater.addandget(person,1);
final int age = personatomicintegerfieldupdater.get(person);
system.out.println(age);
assert age==31 : "更新失败";
}
}
小结
package com.cocurrenttest.atomictest;
import java.util.arrays;
import java.util.list;
import java.util.concurrent.atomic.atomicreference;
import java.util.stream.collectors;
/**
* 说明:todo
* @author carter
* 创建时间: 2019年12月06日 19:36
**/
public class teststream {
public static void main(string[] args) {
integer age = 25 ;
final string name="b";
//some condition to change
name ="bbb";
final list<person> personlist = arrays.aslist(
person.builder().name("aaa").age(10).build(),
person.builder().name("bbb").age(20).build(),
person.builder().name("ccc").age(30).build()
)
.stream()
.filter(item -> item.getage() >= age)
.filter(item->item.getname().contains(name))
.collect(collectors.tolist());
system.out.println(personlist);
}
public static void main2(string[] args) {
integer age = 25 ;
final atomicreference<string> name=new atomicreference<>("b");
//some condition to change
name.set("bbb");;
final list<person> personlist = arrays.aslist(
person.builder().name("aaa").age(10).build(),
person.builder().name("bbb").age(20).build(),
person.builder().name("ccc").age(30).build()
)
.stream()
.filter(item -> item.getage() >= age)
.filter(item->item.getname().contains(name.get()))
.collect(collectors.tolist());
system.out.println(personlist);
}
}