我们知道在java多线程中使用sychronized和reentrantlock可以保证只有一个线程进入代码块,从而可以保证可见性,顺序性和原则性。但是这样做的效率比较低, 明明是多线程的工作,执行到这一块儿的时候就变成单线程了。
使用volatile修饰变量可以保证其可见性和顺序性,但是却不能保证其原则性,想要实现原则性可以了解下接下来介绍的java多谢的的automic包锁提供的下面工具:
java.util.concurrent.atomic, 在atomic工具包下面有下面这么多个类, 其实用嘴简单的话来介绍其就值解决了一个问题就是,对值进行改变,例如对int值,long值,数组,引用类型,引用类型中的成员变量进行赋值,因为赋值操作不熟原则的,所以想要原子的改变每个值又不使用锁的情况下就可以用这个包的工具帮你解决问题:
x = a
如下截图:
我们可以分成四个类型:
第一个类型:
对基本数据类型进行值得改变:
如图红色部分:
AtomicBoolean
AtomicInteger
AtomicLong
常用到的方法有:
int get() 获取当前值。
void set(int newValue) 设置为给定值。
int addAndGet(int delta) 将给定值与当前值相加返回结果。
int decrementAndGet() 当前值减 1并返回结果。
int incrementAndGet() 当前值加 1变返回结果。
@Test
public void testAtomicInterger(){
AtomicInteger integer = new AtomicInteger(0);
System.out.println(integer.get()); //i
integer.set(10); //i=10
System.out.println(integer.get());//i
System.out.println(integer.addAndGet(10));//i=i+10
System.out.println(integer.incrementAndGet());//++i
System.out.println(integer.decrementAndGet());//--i
}
执行结果:
第二个类型:
对数组进行原则操作
AtomicIntegerArray 原子更新int型数组
AtomicLongArray 原子更新long型数组
AtomicReferenceArray 原子更新引用数组
常用方法:
int get(int i) // i
void set(int i, int newValue) // a[i]=newValue
int length() // a.length()
int getAndAdd(int i, int delta) // a[i]=a[i]+delta
int getAndDecrement(int i) // i++
int getAndIncrement(int i) // i--
AtomicIntegerArray(int length) // new [length] Array()
例子一操作普通数组:
@Test
public void testAtomicArray(){
int [] array = new int[]{1,2,3,4,5};
AtomicIntegerArray atomicArray = new AtomicIntegerArray(array);
System.out.println(atomicArray.get(3));
System.out.println(atomicArray.addAndGet(0,10));
System.out.println(atomicArray.incrementAndGet(0));
System.out.println(atomicArray.decrementAndGet(0));
for (int i = 0; i < atomicArray.length(); i++) {
System.out.println(atomicArray.get(i));
}
}
执行结果:
实例 二,操作二维数组:
@Test
public void testAtomic2Array(){
int [] array0 = new int[]{1,2,3,4,5};
int [] array1 = new int[]{6,7,8,9,10};
AtomicIntegerArray atomicArray1 = new AtomicIntegerArray(array0);
AtomicIntegerArray atomicArray2 = new AtomicIntegerArray(array1);
AtomicIntegerArray [] refA = new AtomicIntegerArray []{atomicArray1,atomicArray2};
AtomicReferenceArray <AtomicIntegerArray> refArray = new AtomicReferenceArray(refA);
System.out.println( refArray.get(0).get(0));
System.out.println( refArray.get(1).get(0));
}
执行结果:
第三个类型:
对类中的成员变量进行值更改, 注意类里面的变量不能是private的,而且必须由valotile修饰。
AtomicIntegerFieldUpdater 原子更新整型的字段的更新器
AtomicLongFieldUpdater 原子更新长整型的字段更新器
AtomicReferenceFieldUpdater 原子更新引用类型的字段更新器
@Test
public void testAtomicField(){
Child child = new Child();
AtomicIntegerFieldUpdater intField = AtomicIntegerFieldUpdater.newUpdater(Child.class,"age");
AtomicReferenceFieldUpdater strField = AtomicReferenceFieldUpdater.newUpdater(Child.class,String.class,"name");
intField.set(child,20);
strField.set(child,"Allen");
System.out.println("age : " + child.age);
System.out.println("name : " + child.name);
}
public class Child {
public volatile String name;
public volatile int age;
}
第四个类型
AtomicReference 引用类型的变量赋值改变
AtomicStampedReference 引用类型的变量赋值改变并带版本号,解决ABA问题
AtomicReference 实现的功能就是和Child c = c1; 这样的功能,目的是实现原则性的引用类型赋值。
AtomicStampedReference 加了版本功能,每次赋值必须传入争取的版本号, 如果版本号不对就不会赋值成功如下例子。
@Test
public void testAtomicRef(){
Child child = new Child("Allen",18);
Child child1 = new Child("LiSang",19);
Child child2 = new Child("Wang",20);
AtomicReference <Child> childRef= new AtomicReference<Child> (child);
childRef.set(child1);
System.out.println(childRef.get().name);
AtomicInteger atomicInt = new AtomicInteger(0);
AtomicStampedReference <Child> childSRef= new AtomicStampedReference<Child> (child,atomicInt.getAndIncrement());
childSRef.set(child1,atomicInt.getAndIncrement());
System.out.println(childRef.get().name+ " " +atomicInt.get());
childSRef.set(child2,atomicInt.getAndIncrement());
System.out.println(childRef.get().name+ " " +atomicInt.get());
childSRef.set(child,0);
System.out.println(childRef.get().name+ " " +atomicInt.get());
}
public class Child {
public volatile String name;
public volatile int age;
public Child (){
}
public Child (String name, int age){
this.name = name;
this.age = age;
}
}
执行结果: