本文共 3166 字,大约阅读时间需要 10 分钟。
变量使用了volatile关键字
package automitic;public class Mydata { volatile int num=0; public void addto60(){ this.num=60; } public void addplusplus(){ num++; }}
开启20个前程执行1000次num++
package automitic;//验证volatile不保证原子性public class VolatileDemo { public static void main(String[] args) { Mydata mydata=new Mydata(); //资源类 //创建20个线程,每个线程操作num++ 1000次 for(int i=0; i<20;i++){ new Thread(()->{ for(int j=0;j<1000;j++) mydata.addplusplus(); },String.valueOf(i)).start(); } //等待20个线程执行结束后,用main线程取值,如果volatile保证原子性,那应该会得到值20000 while (Thread.activeCount()>2){ //这里为什么用2,因为默认后台就会有两个线程,main线程和GC线程 Thread.yield(); } //控制多线程结束后再..的最好方法 System.out.println(Thread.currentThread().getName()+"\t任务完成,num值现在为:"+mydata.num); }}
执行结果
发现执行多次的值都不一样,也都不是想当然的20000,当然也有是20000的可能,偶然而已。
所以证明volatile不保证原子性。
volatile不保证原子性,也再次体现了它是一个轻量级,乞丐版
为什么num++的值小于20000
因为出现了多线程,出现了丢失写值得情况
比如线程1,2,3都从主物理内存中拿到了num初始值0,在各自得工作内存中,各自自增1, 三个线程都要向主物理内存中写,1线程写入主内存,2,3线程挂起,然后num得值变为1,通知2,3,进程num值已经为1了。但是因为线程非常快,线程2或者3又可能再次把1又写入了主内存,写覆盖,造成了写数据丢失。所以最后得值就很大可能低于20000.恰好等于20000的几率极小。
number++在多线程下是非线程安全的,加synchronized,就能保证是线程安全了
package automitic;public class Mydata { volatile int num=0; public void addto60(){ this.num=60; } public synchronized void addplusplus(){ num++; }}
加了之后就计算都是20000了
但是使用synchronized,有点大材小用
//使用JUP下的AtomicInteger
AtomicInteger atomicInteger= new AtomicInteger();//初始值为0package Atomic;import java.util.concurrent.atomic.AtomicInteger;public class Mydata { //基本类型 volatile int num=0; public void addto60(){ this.num=60; } public void addplusplus(){ num++; } //使用带原子性的num++ AtomicInteger atomicInteger= new AtomicInteger();//初始值为0 public void addAtomic(){ atomicInteger.getAndIncrement(); //增1 }}
package Atomic;//验证volatile不保证原子性public class VolatileDemo { public static void main(String[] args) { Mydata mydata=new Mydata(); //资源类 //创建20个线程,每个线程操作num++ 1000次 for(int i=0; i<20;i++){ new Thread(()->{ for(int j=0;j<1000;j++) // mydata.addplusplus(); mydata.addmyAtomic(); },String.valueOf(i)).start(); } //等待20个线程执行结束后,用main线程取值,如果volatile保证原子性,那应该会得到值20000 while (Thread.activeCount()>2){ //这里为什么用2,因为默认后台就会有两个线程,main线程和GC线程 Thread.yield(); } //控制多线程结束后再..的最好方法 // System.out.println(Thread.currentThread().getName()+"\t任务完成,int类型 num值现在为:"+mydata.num); System.out.println(Thread.currentThread().getName()+"\t任务完成,AtomicInterger类型 值在为:"+mydata.atomicInteger); }}
运行结果,就一直是20000
1.java后台默认的两个线程 :main, GC
2.主线程main等待其他线程结束后再执行的最佳方法while (Thread.activeCount()>2){ //这里为什么用2,因为默认后台就会有两个线程,main线程和GC线程 Thread.yield(); //控制多线程结束后再..的最好方法 }
PS:学习笔记,尚硅谷,周阳大佬
转载地址:http://vvfdi.baihongyu.com/