1.可见性
2.原子性
3.有序性
/*
* Copyright (C), 2013-2019, 天津大海云科技有限公司
*/
package com.jikang.entity;
import java.util.concurrent.TimeUnit;
/**
* @author yangjikang
* @date 2019/6/5 17:26
* @description 模拟volatile可见性案例
* @modified By yangjikang
*/
public class Sync {
//模拟volatile的可见性
public static void main(String[] args) {
MyThread mt = new MyThread();
//A线程更改number的值
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t线程 coming");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
mt.setNumber();
System.out.println(Thread.currentThread().getName() + "线程 update value :"+mt.number);
},"A1").start();
//
while (mt.number == 0){
//直到main方法读取到numer != 0则跳出循坏
}
System.out.println(Thread.currentThread().getName() + "获取到当前的number:"+mt.number);
}
}
class MyThread {
/*volatile*/ int number = 0;
public void setNumber() {
this.number = 60;
}
}
模拟volatile不保证原子性案例,如下
/*
* Copyright (C), 2013-2019, 天津大海云科技有限公司
*/
package com.jikang.entity;
/**
* @author yangjikang
* @date 2019/6/5 17:26
* @description 模拟volatile不保证原子性案例
* @modified By yangjikang
*/
public class Sync {
//模拟volatile不保证原子性
public static void main(String[] args) {
MyThread mt = new MyThread();
//模拟20个线程调用addNumber方法给number++.
for (int i = 0; i < 40 ; i++) {
new Thread(() -> {
for (int j = 0; j <10000; j++) {
mt.addNumber();
}
},String.valueOf(i)).start();
}
//等待上面20个线程都计算完成,再用main线程获取修改之后的值
while (Thread.activeCount() > 2){
Thread.yield();
}
System.out.println(Thread.currentThread().getName() + "获取到当前的number:"+mt.number);
}
}
class MyThread {
volatile int number = 0;
public void setNumber() {
this.number = 60;
}
public void addNumber() {
number ++;
}
}
/*
* Copyright (C), 2013-2019, 天津大海云科技有限公司
*/
package com.jikang.entity;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author yangjikang
* @date 2019/6/5 17:26
* @description 模拟解决volatile不保证原子性的问题
* @modified By yangjikang
*/
public class Sych {
public static void main(String[] args) {
MyThread mt = new MyThread();
//模拟20个线程调用addNumber方法给number++.
for (int i = 0; i < 40 ; i++) {
new Thread(() -> {
for (int j = 0; j <10000; j++) {
mt.addNumber();
mt.addAtomicNumber();
}
},String.valueOf(i)).start();
}
//等待上面20个线程都计算完成,再用main线程获取修改之后的值
while (Thread.activeCount() > 2){
Thread.yield();
}
System.out.println(Thread.currentThread().getName() + "获取到当前的number:"+mt.number);
System.out.println(Thread.currentThread().getName() + "获取到Atomic方法的number:"+mt.atomicInteger);
}
}
class MyThread {
volatile int number = 0;
public void setNumber() {
this.number = 60;
}
public void addNumber() {
number ++;
}
//解决volatile不保证原子性
AtomicInteger atomicInteger = new AtomicInteger();
public void addAtomicNumber() {
//原子性的 i++
atomicInteger.getAndIncrement();
}
}
这种效果可能的情况只有99.9%,这里就不实验了,可能试一万次都不一定有效果
一系列问题
CAS就是一个自旋锁
CAS :比较并交换
CAS ==> compareAndSwap,它是一条CPU并发原语
CAS ==> compareAndSwap,它是一条CPU并发原语
UnSafe类
接口调用
1.循环时间长开销大
2.只保证一个共享变量的原子操作
3.引出来ABA问题???
ABA问题的图解,CAS只管开头和结尾不管过程,ABA问题就是这个过程会被修改
这里用的是一个AtomicReference<>
/*
* Copyright (C), 2013-2019, 天津大海云科技有限公司
*/
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;
/**
* @author yangjikang
* @date 2019/6/12 13:40
* @description ABA问题产生
* @modified By yangjikang
*/
public class TestAtomicStampedReference {
//普通的原子引用
static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);
public static void main(String[] args) {
System.out.println("=================下面是ABA问题的模拟场景===================");
//T1线程执行ABA操作
new Thread(()->{
atomicReference.compareAndSet(100,101);
atomicReference.compareAndSet(101,100);
},"T1").start();
//T2线程正常操作数据
new Thread(()->{
//暂停2秒,保证T1线程完成一次ABA操作
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
boolean result = atomicReference.compareAndSet(100, 2019);
System.out.println(Thread.currentThread().getName()+"线程更改成功没有:"+result+",当前数据是:"+atomicReference.get());
},"T2").start();
}
}
这里用是的一个AtomicStampedReference<>
/*
* Copyright (C), 2013-2019, 天津大海云科技有限公司
*/
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;
/**
* @author yangjikang
* @date 2019/6/12 13:40
* @description ABA问题解决
* @modified By yangjikang
*/
public class TestAtomicStampedReference {
//带时间戳(版本号)的原子引用
static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100,1);
public static void main(String[] args) {
System.out.println("=================下面是ABA问题的解决方案===================");
//T3线程执行ABA操作
new Thread(()->{
//获取当前原子版本号
int stamp = atomicStampedReference.getStamp();
//暂停1秒,保证T3线程完成一次ABA操作
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
boolean oneReference = atomicStampedReference.compareAndSet(100, 101,
atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
System.out.println(Thread.currentThread().getName()+"线程更改成功没有:"+oneReference+"第1次更改之后的版本号"+atomicStampedReference.getStamp());
boolean TwoReference = atomicStampedReference.compareAndSet(101, 100,
atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
System.out.println(Thread.currentThread().getName()+"线程更改成功没有:"+TwoReference+"第2次更改之后的版本号"+atomicStampedReference.getStamp());
},"T3").start();
//T4线程正常操作数据
new Thread(()->{
//获取当前原子版本号
int stamp = atomicStampedReference.getStamp();
//暂停3秒,保证T3线程完成一次ABA操作
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
boolean result = atomicStampedReference.compareAndSet(100, 2019,
stamp, stamp + 1);
System.out.println(Thread.currentThread().getName()+"线程更改成功没有:"+result+",当前数据是:"+
atomicStampedReference.getReference()+",当前版本号是"+atomicStampedReference.getStamp());
},"T4").start();
}
}