这一章,我们要来验证volatile关键字不是原子性的,OK,还是用代码来说话。
①.线程类,操作i++ 500次 package com.multiThread.thread;publicclassNumberThreadimplementsRunnable{privatevolatileint num =0;@Overridepublicvoid run(){for(int i =0;i<500;i++){ num++;}}publicint getNum(){return num;}publicvoid setNum(int num){this.num = num;}} ②.测试类,创建5个线程同时执行 package com.multiThread.test.automic;import com.multiThread.thread.NumberThread;publicclassAutomicTest{publicstaticvoid main(String[] args){NumberThread numThread =newNumberThread();for(int i =0;i<5;i++){Thread t =newThread(numThread); t.start();}try{Thread.sleep(1000);}catch(InterruptedException e){ e.printStackTrace();}System.out.println(numThread.getNum());}} 多次运行结果:(正常结果2500居多) 250022822458 为什么造成这种现象? 首先我们要知道i++不是原子操作,是线程不安全的,它分为以下3步: 1.获取i的值 2.执行i+1的操作 3.将结果赋值给i 其次就算变量已经使用volatile关键字来修饰,只能保证读取全局变量num值的时候从主存拿到的是最新的值。 但是当多个线程同时操作自加的时候,如果之前取到的是同一个值,再自加后得到的值是相同的。 解决的方式如下两种: 1.可以使用synchronize关键字进行同步操作,这种情况需要把volatile去掉。因为synchronize本身就会操作工作内存和主内存直接的数据同步,此方式不再赘述。 2.将i++更改为线程安全的原子性操作,使用AtomicInteger替代i++ ①.线程类 package com.multiThread.thread;import java.util.concurrent.atomic.AtomicInteger;publicclassNumberThread2implementsRunnable{privateAtomicInteger num =newAtomicInteger();@Overridepublicvoid run(){for(int i =0;i<500;i++){ num.incrementAndGet();}}publicAtomicInteger getNum(){return num;}publicvoid setNum(AtomicInteger num){this.num = num;}} ②.测试类 package com.multiThread.test.automic;import com.multiThread.thread.NumberThread;import com.multiThread.thread.NumberThread2;publicclassAutomicTest{publicstaticvoid main(String[] args){ NumberThread2 numThread2 =newNumberThread2();for(int i =0;i<5;i++){Thread t =newThread(numThread2); t.start();}try{Thread.sleep(1000);}catch(InterruptedException e){ e.printStackTrace();}System.out.println(numThread2.getNum());}} 运行结果 2500 来自为知笔记(Wiz)转载于:https://www.cnblogs.com/douJiangYouTiao888/p/6473807.html