空白网站建设,做网站需要的信息,网页设计网站的分析,建筑网站首页设计目录1. volatile1.1.什么是volatile1.2.JMM-Java内存模型2 验证volatile的特性2.1 可见性2.2.验证volatile不保证原子性2.3 volatile实现禁止指令重排序3.使用AtomicInteger解决volatile的不能实现原子性的问题3.2 AtomicInteger的方法说明#xff1a;3.3 CAS3.4 应用1. volat…
目录1. volatile1.1.什么是volatile1.2.JMM-Java内存模型2 验证volatile的特性2.1 可见性2.2.验证volatile不保证原子性2.3 volatile实现禁止指令重排序3.使用AtomicInteger解决volatile的不能实现原子性的问题3.2 AtomicInteger的方法说明3.3 CAS3.4 应用1. volatile
1.1.什么是volatile
volatile是Java虚拟机提供的轻量级的同步机制保证了可见性和有序性禁止指令重排序保证了JMM三个特性中的两个
1.2.JMM-Java内存模型 JMM的三个特性 可见性、有序性、原子性 可见性
线程在自己的工作内存中修改了从主内存中拷贝的共享变量副本后并把修改后的值重新传到主内存中进行更新。这时我们要保证其他线程第一时间也可以得到共享变量已经被修改的通知。这样就保证了线程之间的一个可见性因为线程间是不能直接访问对方的工作内存所以可以从主内存下手 有序性 禁止指令重排避免多线程的环境下程序出现乱序执行的现象。 指令重排计算机在执行程序时为了提高性能编译器和处理器常常回对指令做重排 原子性 某个线程正在做某个具体业务时中间不可以被加塞或者被分割。需要整体完整要么同时成功要么同时失败。
2 验证volatile的特性
2.1 可见性
package volatileTest;class MyData{volatile int num0;public void addTo60(){this.num70;}
}
public class Test1 {public static void main(String[] args) {MyData datanew MyData();new Thread(()-{System.out.println(Thread.currentThread().getName() 进来了。。。);try {Thread.sleep(3);//保证主线程已经得到了num0} catch (InterruptedException e) {e.printStackTrace();}data.addTo60();System.out.println(Thread.currentThread().getName()将值改为data.num);},AAA).start();while (data.num0){}System.out.println(Thread.currentThread().getName() 近啦了);System.out.println(Thread.currentThread().getName()获取numdata.num);}
} 说明num被voalite修饰AAA线程执行了addTo60后将num的值改为70如果没有可见性的话主线程main是不会感受到num已经被修改了应该会一直循环但结果表明main并没有一直在循环体中而是可以得到70这个值所以表明volatile修饰了变量使其具有可见性
2.2.验证volatile不保证原子性
package volitileTest;
/*** 验证volatile不保证原子性*/
class Num{volatile int num0;//20个线程对num进行加1操作每个线程执行1000次理论上应该为20000public void numAdd(){num;}
}
public class Test2 {public static void main(String[] args) {Num objnew Num();for(int i1;i20;i) {new Thread(()-{for(int j0;j1000;j){obj.numAdd();}},String.valueOf(i)).start();}while (Thread.activeCount() 2) {Thread.yield();}System.out.println(Thread.currentThread().getName()获取结果为obj.num);}
} 说明理论值应该是20000但实际结果小于20000. 为什么不能保证原子性因为没有锁线程会进行争抢不能及时将修改后的值写回主内存
2.3 volatile实现禁止指令重排序 3.使用AtomicInteger解决volatile的不能实现原子性的问题
package volitileTest;import java.util.concurrent.atomic.AtomicInteger;/*** 验证volatile不保证原子性* 解决不保证原子性的问题--AtomicInteger*/
class Num{volatile int num0;//20个线程对num进行加1操作理论上应该为20000public void numAdd(){num;}AtomicInteger atomicIntegernew AtomicInteger();public void myAtomicAdd(){atomicInteger.getAndIncrement();//每次加1}
}
public class Test2 {public static void main(String[] args) {Num objnew Num();for(int i1;i20;i) {new Thread(()-{for(int j0;j1000;j){obj.numAdd();obj.myAtomicAdd();}},String.valueOf(i)).start();}while (Thread.activeCount() 2) {Thread.yield();}System.out.println(Thread.currentThread().getName()获取结果为obj.num);System.out.println(Thread.currentThread().getName()获取结果为obj.atomicInteger);}
} 说明可以看到使用了AtomicInteger后得到的结果与预期相符
3.2 AtomicInteger的方法说明
1.incermentAndGet()—相当于i,先加1再返回 2.getAndIncrement()–相当于i,先返回再加1 3.相同点内部都调用了unsafe类的getAndAddInt方法 可以看到为什么AtomicInteger能实现原子性因为原理是CAS
3.3 CAS
CASCompare and Set CAS是指在这个操作中如果AtomicInteger的当前值是prev那么就更新为一个预期值这里预期值是当前值加1返回true。如果AtomicInteger的当前值不是prev就什么也不干返回false。通过CAS操作并配合do … while循环即使其他线程修改了AtomicInteger的值最终的结果也是正确的。
3.4 应用
使用java.util.concurrent.atomic提供的原子操作可以简化多线程编程
1.原子操作实现了无锁的线程安全
2.适用于计数器累加器等。