多线程情况下,要保证操作数据的原子性,
原子性:就是不能再往下细分的操作,JAVA 的原子操作的原理 主要是利用了CAS原理,限于篇幅 建议移步 大神的关于CAS原理的文章
以为为类操作的API和相关注释,直接上源码
原子更新基本类型类:
package com.hhx.offline_tools.encode.Atomic;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
/**
* 原子更新基本类型类
*
* 1、AtomicBoolean 原子更新布尔类型值
* 2、AtomicInteger 原子更新整型
* 3、AtomicLong 原子更新 长整型
* @author 清水贤人
*
*/
public class AtomicBaseType {
// 原子方式更新基本类型,Atomic 包提供以下3个类
static AtomicInteger aInteger = new AtomicInteger(1); //写1 代表默认值为1
static AtomicBoolean aBoolean = new AtomicBoolean(); //括号中可以自定义默认值,不定义默认为false
static AtomicLong aLong = new AtomicLong(); //默认值为0
public static void main(String[] args) {
/**
* AtomicInteger API
* get()是获取当前的值
* addAndGet(X)是以原子方式将输入的值与实例中的值相加 并返回结果
* compareAndSet(x,y)先获取当前的值,如果输入的x值和当前值相等,则吧当前值变为y,否则保持不变
* getAndIncrement 以原子方式将当前值加1,同时返回加1之前的值
* decrementAndGet 以原子形式减去1 并返回减1之后的值
* getAndSet(x) 以原子方式设置值为x 并返回原始值
*/
System.out.println(aInteger.get());
System.out.println(aInteger.addAndGet(1));
System.out.println(aInteger.compareAndSet(1, 5));
System.out.println(aInteger.getAndIncrement());
System.out.println(aInteger.decrementAndGet());
System.out.println(aInteger.getAndSet(8));
System.out.println(aInteger.get());
//由于 AtomicBoolean,AtomicLong API和AtomicInteger 相差无几 在这里不列出
}
}
原子更新数组类型类:
/**
*
*/
package com.hhx.offline_tools.encode.Atomic;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.concurrent.atomic.AtomicLongArray;
import java.util.concurrent.atomic.AtomicReferenceArray;
/**
* 原子更新数组类型类
*
* 1、AtomicIntegerArray 原子更新整数类型里的元素
* 2、AtomicLongArray 原子更新长整型数组里的元素
* 3、AtomicReferenceArray 原子更新引用类型数组里的元素
* @author 清水贤人
*
*/
public class AtomicArrayType {
// 定义数组
static int[] value = new int[] { 7, 2 };
// 原子更新整数类型里 的元素,这里的value 复制时吧里面的两个元素给初始化到这个数组
static AtomicIntegerArray integerArray = new AtomicIntegerArray(value);
// 原子更新长整形类型数组里的内容
static AtomicLongArray longArray = new AtomicLongArray(0);
//原子更新引用类型数组里的元素
static AtomicReferenceArray referenceArray = new AtomicReferenceArray(0);
public static void main(String[] args) {
//integerArray.getAndSet(0, 8);// 获取数组的第0个元素 并赋值为8
//System.out.println(integerArray.get(0)); // 这个是获取修改后的值 为8
/**
* 数组value 通过构造方法传递进去,
* 然后AtomicIntegerArray 会将当前的数组复制一份,
* 所以当AtomicIntegerArray对内部元素进行修改的时候
* 不会影响传入的数组
*/
//System.out.println(value[0]); // 原始数组的值不变 得到的依旧是7
/**
* addAndGet 方法
* 第一个入参是 数组中的元素位置(i)
* 第二个元素是 准备要加的值(即加数)
* 运行后的结果 的返回值就是 数组中的 i和加数的 加法运算值
*/
//System.out.println(integerArray.addAndGet(0, 2));
/**
* compareAndSe 方法的返回值是boolean
* 第一个参数的是数组的下标
* 第二个参数是期望的元素的指定下标的值
* 第三个参数 如果准备修改为的值
*
* 如果第二个元素和数组下标指定的元素的值 相等,则将该小标的值修改为第三个参数的值,返回true
* 反之,不做任何修改 返货false
*/
//System.out.println(integerArray.compareAndSet(0, 7, 9));
/**
* 对指定数组下标的元素进行加1 操作
*/
System.out.println(integerArray.incrementAndGet(0));
// 其余的和AtomicIntegerArray 相差无几 不在列出
}
}
原子更新字段类:
/**
*
*/
package com.hhx.offline_tools.encode.Atomic;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import org.omg.CORBA.ObjectHolder;
/**
* 原子更新字段类
* 类为:
* 1、AtomicIntegerFieldUpdater 原子更新整形的字段的更新器
* 2、AtomicLongFieldUpdater 原子更新长整形字段的更新器
* 3、AtomicStampedReference 原子更新带有版本号的引用类型
* @author 清水贤人
*
*/
public class AtomicFieldType {
/**
* 创建原子更新器,并设置需要更新的对象类和对象的属性
*
* 原子更新字段需要两部:
* 1、因为原子更新字段都是抽象类,每次使用的时候,必须使用静态方法NewUpdater(),创建一个更新器
* 并且需要设置需要更新的类和属性
* 2、更新字段,字段必须使用public volatile修饰
*/
private static AtomicIntegerFieldUpdater<User> atomicIntegerFieldUpdater = AtomicIntegerFieldUpdater.
newUpdater(User.class, "old");
public static void main(String[] args) {
User user = new User("hhx", 8);
// 增整了1 但是会输出旧的值
System.out.println(atomicIntegerFieldUpdater.getAndIncrement(user));
// 直接输出新值(增长后的)
System.out.println(atomicIntegerFieldUpdater.get(user));
}
// User 实体
public static class User {
private String name;
public volatile int old;
volatile Integer sex=3;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getOld() {
return old;
}
public void setOld(int old) {
this.old = old;
}
public User(String name, int old) {
super();
this.name = name;
this.old = old;
}
}
}
原子更新引用类型:
/**
*
*/
package com.hhx.offline_tools.encode.Atomic;
import java.util.concurrent.atomic.AtomicMarkableReference;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
/**
*
* 原子更新引用类型
*
* 1、AtomicReference 原子更新引用或类型的字段
* 2、AtomicReferenceFieldUpdater 原子更新带有引用类型的字段
* 3、AtomicMarkableReference 原子更新带有标记位的引用类型
*
* @author 清水贤人
*
*/
public class AtomicReferType {
public static AtomicReference<User> atomicUser = new AtomicReference<User>();
public static void main(String[] args) {
User user = new User("hhx" , 8);
atomicUser.set(user);
User updateUser = new User("hhx1" , 81);
/**
* compareAndSet
* 这两个方法 目前是一样的,但是源码的注释不一样
* 老外给的解释是:我们暴保留后期会更改的权利,只不过暂时没有变
* 建议分开使用
*/
System.out.println(atomicUser.compareAndSet(user, updateUser));
System.out.println(atomicUser.weakCompareAndSet(user, updateUser));
/**
* AtomicReferenceFieldUpdater
* 他能对指定类的指定volatile字段进行原子更新(不能声明为private)
* 第一个参数为要更新的类的类名
* 第二个字段为要更新的字段名属性(包装类)
* 第三个字段为要更新的字段的 字段名(用双引号包裹)
*/
AtomicReferenceFieldUpdater fileUpload = AtomicReferenceFieldUpdater.
newUpdater(User.class, Integer.class, "sex");
fileUpload.compareAndSet(user, user.sex, 6);
System.out.println(user.sex);
}
// User 实体
static class User {
private String name;
private int old;
volatile Integer sex=3;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getOld() {
return old;
}
public void setOld(int old) {
this.old = old;
}
public User(String name, int old) {
super();
this.name = name;
this.old = old;
}
}
}