版权声明:欢迎转载大宇的博客,转载请注明出处: https://blog.csdn.net/yanluandai1985/article/details/82688890
参考文章:https://blog.csdn.net/tlk20071/article/details/75729675
一、自增:不加锁线程不安全
public class AtomicDemo {
//定义一个共享变量
private int value;
//获取共享变量
public int getValue() {
return value;
}
//为共享变量设置新值
public void setValue(int value) {
this.value = value;
}
public static void main(String[] args) throws InterruptedException {
//创建一个有共享变量的对象
AtomicDemo demo = new AtomicDemo();
//创建线程A、B
ThreadA threadA = new ThreadA(demo);
ThreadB threadB = new ThreadB(demo);
//启动线程A、B
threadA.start();
threadB.start();
//主函数等待运行结束
threadA.join();
threadB.join();
//获取运算结果
System.out.println(demo.getValue());
}
}
class ThreadA extends Thread {
private AtomicDemo demo;
public ThreadA(AtomicDemo demo) {
this.demo = demo;
}
@Override
public void run() {
//任务是为demo的value变量自增十万次
for (int i = 0; i < 100000; i++) {
demo.setValue(demo.getValue()+1);
}
}
}
class ThreadB extends Thread {
private AtomicDemo demo;
public ThreadB(AtomicDemo demo) {
this.demo = demo;
}
@Override
public void run() {
//任务是为demo的value变量自增十万次
for (int i = 0; i < 100000; i++) {
demo.setValue(demo.getValue()+1);
}
}
}
运行结果:150450
上述代码的运行结果说明,value变量线程不安全。一般的做法是,让线程A与线程B共享一个同步锁。
二、无锁:使用CAS操作 原子更新基本类型
import java.util.concurrent.atomic.AtomicInteger;
/**
* Created by Jay.Zhou on 2018/9/13.
*/
public class AtomicDemo {
//共享变量用原子操作类
private AtomicInteger integer;
public AtomicDemo() {
integer = new AtomicInteger(0);
}
public AtomicInteger getInteger() {
return integer;
}
public void setInteger(AtomicInteger integer) {
this.integer = integer;
}
public static void main(String[] args) throws InterruptedException {
//创建一个有共享变量的对象
AtomicDemo demo = new AtomicDemo();
//创建线程A、B
ThreadA threadA = new ThreadA(demo);
ThreadB threadB = new ThreadB(demo);
//启动线程A、B
threadA.start();
threadB.start();
//主函数等待运行结束
threadA.join();
threadB.join();
//获取运算结果
System.out.println(demo.getInteger());
}
}
class ThreadA extends Thread {
private AtomicDemo demo;
public ThreadA(AtomicDemo demo) {
this.demo = demo;
}
@Override
public void run() {
//任务是为demo的共享变量自增十万次
for (int i = 0; i < 100000; i++) {
//CAS操作自增
demo.getInteger().incrementAndGet();
}
}
}
class ThreadB extends Thread {
private AtomicDemo demo;
public ThreadB(AtomicDemo demo) {
this.demo = demo;
}
@Override
public void run() {
//任务是为demo的共享变量自增十万次
for (int i = 0; i < 100000; i++) {
//CAS操作自增
demo.getInteger().incrementAndGet();
}
}
}
运行结果:200000
使用CAS操作的原子操作类,线程安全,不用加锁
三、无锁:使用CAS操作 原子更新引用类型
import java.util.concurrent.atomic.AtomicStampedReference;
/**
* Created by Jay.Zhou on 2018/9/13.
*/
public class AtomicStrampReferenceDemo {
public static void main(String[] args) throws InterruptedException {
User A = new User();
User B = new User();
//默认的原子操作类的对象是 A,版本为1
AtomicStampedReference<User> reference = new AtomicStampedReference<User>(A, 1);
for (int i = 0; i < 10; i++) {
//开启是个线程,如果是预期版本,则操作reference内部维护的对象
new Thread(() -> {
/**
* V expectedReference, 就是你提供的对象 CAS(V,E,N)的E
V newReference, 如果 E == V ,那么把 这个新的引用赋值给 共享变量
int expectedStamp, 你提供的版本号
int newStamp 你提供的版本号如果与共享变量的版本号一致,那么把这个新的版本号赋值给共享变量版本号
*/
//第一个与第三个参数,A1,拿去与reference的构造函数中的共享变量比较
//如果比较一致,返回true,并且将内部的数据设置为 B2
if (reference.compareAndSet(A, B, 1, 2)) {
System.out.println("user版本升级");
}
}).start();
}
//等待设置结束
Thread.sleep(2000);
//获取版本号为2的User对象
User C = reference.get(new int[]{2});
//比较是否是同一个对象
System.out.println(C == B);
}
}
class User {
}
/**
user版本升级
true
*/
四、原子更新引用类型
import java.util.concurrent.atomic.AtomicReference;
public class AtomicReferenceTest {
public static AtomicReference<User> atomicUserRef = new AtomicReference<User>();
public static void main(String[] args) {
User user = new User("测试1", 10);
atomicUserRef.set(user);
User updateUser = new User("测试2", 22);
atomicUserRef.compareAndSet(user, updateUser);
System.out.println(atomicUserRef.get().getName());
System.out.println(atomicUserRef.get().getPassword());
}
static class User {
private String name;
private int password;
//..
}
}
测试2
22
五、原子更新字段类型
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
public class AtomicIntegerFieldUpdaterTest {
// 创建原子更新器,并设置需要更新的对象类和对象的属性
private static AtomicIntegerFieldUpdater<User> a = AtomicIntegerFieldUpdater.newUpdater(User.class, "old");
public static void main(String[] args) {
// 设置柯南的年龄是10岁
User conan = new User("conan", 10);
// 柯南长了一岁,但是仍然会输出旧的年龄
System.out.println(a.getAndIncrement(conan));
// 输出柯南现在的年龄
System.out.println(a.get(conan));
}
public static class User {
private String name;
public volatile int old;
public User(String name, int old) {
this.name = name;
this.old = old;
}
public String getName() {
return name;
}
public int getOld() {
return old;
}
}
}
六、原子更新数组类型
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicIntegerArray;
public class AtomicReferenceTest {
private static int[] value = new int[]{1, 2, 3, 4, 5};
private static AtomicIntegerArray atomic =
new AtomicIntegerArray(value);
public static void main(String[] args) {
atomic.getAndSet(2, 100);
System.out.println(Arrays.toString(value));//[1, 2, 3, 4, 5] 原来的不改动
System.out.println(atomic.toString());//[1, 2, 100, 4, 5]
}
}