关键做用是使变量在多个线程之间可见java
public class VolativeText { public static void main(String[] args) throws InterruptedException { Student student=new Student(); new Thread(new Runnable() { @Override public void run() { student.GetMethon(); } }).start(); Thread.sleep(1000);//睡眠以后修改布尔值 student.GetName(false);//改变布尔值以结束程序运行 } static class Student { public boolean flag=true; public Student GetName(boolean flag) { this.flag=flag; return this; } public void GetMethon() { System.out.println("开始"); while (flag){//死循环 } System.out.println("结束"); } } }
程序并无由于我修改以后结束运行,由于线程对共享变量具备不可见性,main线程修改布尔值以后,子线程看不到值的修改。所以要想实现线程的可见性这里能够加上volative关键字修饰公共变量算法
volative关键字的做用:使线程在强制公共内存中读取变量值,保证可见性数组
public class Text10 extends Thread { private volatile static int count; @Override public void run() { Addcount(); } public static void Addcount() { for (int i = 0; i < 1000; i++) { count++; } System.out.println(Thread.currentThread().getName()+"-->"+count); } public static void main(String[] args) { for (int i = 0; i < 10; i++) { Text10 text10=new Text10(); text10.start(); } } }
按道理输出1000的整数倍数才对,可是变量在自增的过程当中没有更新到又被读取再修改,所以volatile不具有原子性,正确办法将方法加上synchronized关键字安全
volatile关键字是线程同步的轻量级实现,因此volatile性能确定比synchronized要好,volatile只能修饰变量,而synchronized能够修饰方法代码块,在开发中使用synchronized比例仍是挺大的。多线程
多线程访问volatile变量不会发生阻塞,而synchronized可能会阻塞。dom
volatile能保证数据的可见性,可是不能保证原子性,而synchronized能够保证原子性,也能够保证可见性,由于ide
synchronized会将线程的工做内存和主内存进行同步性能
volatile关键字保证多个线程之间的可见性,synchronized关键字解决线程访问公共资源的同步性。this
区别 | synchronized | volatile |
---|---|---|
使用上 | 只能用于修饰方法、代码块 | 只能修饰实例变量或者类关键字 |
原子性保证 | 能保证,锁能够保护数据不被打断 | 没法保证 |
可见性保证 | 能保证,排它方式使同步代码串行 | 能保证,能够读取公共变量 |
有序性保证 | 能保证,在同步串行的时候 | 能保证,禁止JVM以及处理器进行排序 |
阻塞状况 | 会发生阻塞 | 不会发生阻塞 |
i++不是原子操做,除了使用synchronized进行同步,也可使用AtomicInteger/AtomicLong进行实现atom
import java.util.concurrent.atomic.AtomicInteger; public class Text10 extends Thread { private static AtomicInteger count=new AtomicInteger(); @Override public void run() { AddCount(); } public static void AddCount() { for (int i = 0; i < 1000; i++) { count.getAndIncrement();//至关于i++ //count.incrementAndGet();//至关于++i } System.out.println(Thread.currentThread().getName()+"-->"+count.get()); } public static void main(String[] args) { for (int i = 0; i < 10; i++) { Text10 text10=new Text10(); text10.start(); } } }
CAS(Compare And Swap)是由硬件实现的,
CAS能够将read(读)-modify(修改)-write(写)转化为原子操做
i++自增过程:
从主内存调取i变量值
对i值加1
再把加1事后的值保存到主内存
CAS原理:在把数据更新到主内存时,再次读取主内存变量的值,若是如今变量的值与指望的值同样就更新。
public class CASText { public static void main(String[] args) { CASControl casControl=new CASControl(); for (int i = 0; i <10000 ; i++) { new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"==>"+casControl.incrementAndGet()); } }).start(); } } } class CASControl { volatile static long value;//使用volatile修饰线程可见性 public long getValue() { return value; } private boolean Expect(long oldValue,long newValue) { synchronized (this) { if(value==oldValue) { value=newValue; return true; } else return false; } } public long incrementAndGet() { long oldvalue; long newValue; do { oldvalue=value; newValue=oldvalue+1; }while (!Expect(oldvalue, newValue)); return newValue; } }
CAS实现原子操做背后有一个假设:共享变量当前值与当前线程提供的指望值相同,就认为变量没有被其余线程过。
实际上这种假设不必定成立,假如count=0
A线程对count值修改成10
B线程对count值修改成30
C线程对count值修改成0
当前线程看到count=0,不能认为count没有被其余线程更新,这种结果是否能被接受?
这就是CAS中的ABS问题即共享变量通过了A=》B=》A的更改
是否可以接受ABA问题跟算法实现有关
若是想要规避ABA问题,能够为共享变量引入一个修订号,或者时间戳,每次修改共享变量值,相应的修订号加1.,就会变动为[A,0]=>[B,1]=>[A,2],每次对共享变量的修改都会致使共享变量的增长,经过这个标识就能够判断。AtomicStampedReference类就是基于这个思想产生的。
原子类变量是基于CAS实现的,当对共享变量进行read(读)-modify(修改)-write(写)操做时,经过原子类变量能够保障原子性与可见性,对变量的read(读)-modify(修改)-write(写)操做不是指一个简单的赋值,而是变量的新值,依赖变量的旧值,如自增操做i++,因为volatile只能保证原子的可见性,而不能保证原子性,原变量类内部就是一个借助volatile变量,而且保障了该变量的read-modify-wirte操做的原子性,有时把原子变量看做一个加强的volatile变量,原子变量类有12个
分组 | 原子变量类 |
---|---|
基础数据型 | AtomicInteger、AtomicLong、AtomicBoolean |
数组型 | AtomicIntegerArry、AtomicLongArry、AtomicReferenceArry |
字段更新器 | AtomocIntegerFiledUpdater、AtomicLongFieldUpdate、AtomicReferenceFiledUpdater |
引用型 | AtomicReference、AtomicStampedReference、AtomicMarkableReference |
import java.util.Random; import java.util.concurrent.atomic.AtomicLong; public class Text15 { //构造方法私有化 private Text15(){} //私有静态对象 private static final Text15 text=new Text15(); //公共静态方法返回该类的实例 public static Text15 getInstance() { return text; } //使用原子类记录保存请求总数 成功数 失败数 private final AtomicLong RequestCount=new AtomicLong(0); private final AtomicLong SuccessCount=new AtomicLong(0); private final AtomicLong FailCount=new AtomicLong(0); //进行自增 public void RequestCount() { RequestCount.incrementAndGet(); } public void SuccessCount() { SuccessCount.incrementAndGet(); } public void FailCount() { FailCount.incrementAndGet(); } //查看总数 public long GetRequestCount() { return RequestCount.get(); } public long GetSuccessCount() { return SuccessCount.get(); } public long GetFailCount() { return FailCount.get(); } } class Text16 { public static void main(String[] args) throws InterruptedException { new Thread(new Runnable() { @Override public void run() { for (int i = 0; i <1000 ; i++) { Text15.getInstance().RequestCount();//请求数量 int num=new Random().nextInt(); if(num%2==0)//若是是偶数就成功 { Text15.getInstance().SuccessCount(); } else Text15.getInstance().FailCount(); } } }).start(); Thread.sleep(1000); System.out.println("请求总数:"+Text15.getInstance().GetRequestCount()); System.out.println("请求成功"+Text15.getInstance().GetSuccessCount()); System.out.println("请求失败"+Text15.getInstance().GetFailCount()); } }