- public class AtomicTest {
- private static volatile int counter = 0;
-
- public static void main(String[] args) {
-
- for (int i = 0; i < 10; i++) {
- Thread thread = new Thread(() -> {
- for (int j = 0; j < 10000; j++) {
- //synchronized (AtomicTest.class) {
- counter++;
- // }
- }
-
- });
- thread.start();
- }
-
- try {
- Thread.sleep(3000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- //思考counter=?
- System.out.println(counter);
-
- }
-
- }
- @Slf4j
- public class VisibilityTest {
-
- // volatile -> lock addl $0x0,(%rsp)
- private boolean flag = true;
- // private volatile boolean flag = true;
- //private volatile int count;
-
-
- public synchronized void refresh() {
- // 希望结束数据加载工作
- flag = false;
- System.out.println(Thread.currentThread().getName() + "修改flag:"+flag);
- }
-
- public void load() {
- System.out.println(Thread.currentThread().getName() + "开始执行.....");
- while (flag) {
- //TODO 业务逻辑:加载数据
- //shortWait(10000);
- //synchronized可以保证可见性
- //System.out.println("正在加载数据......");
- // count++;
- //添加一个内存屏障 可以保证可见性
- //UnsafeFactory.getUnsafe().storeFence();
- // try {
- // Thread.sleep(0);
- // } catch (InterruptedException e) {
- // throw new RuntimeException(e);
- // }
- //Thread.yield(); //让出cpu使用权
-
- }
-
- System.out.println(Thread.currentThread().getName() + "数据加载完成,跳出循环");
- }
-
-
- public static void main(String[] args) throws InterruptedException {
- VisibilityTest test = new VisibilityTest();
-
-
- // 线程threadA模拟数据加载场景
- Thread threadA = new Thread(() -> test.load(), "threadA");
- threadA.start();
-
- // 让threadA先执行一会儿后再启动线程B
- Thread.sleep(1000);
-
- // 线程threadB通过修改flag控制threadA的执行时间,数据加载可以结束了
- Thread threadB = new Thread(() -> test.refresh(), "threadB");
- threadB.start();
-
- }
当flag没有volatile修饰时,不可见,执行结果线程A跳不出循环
运行结果:threadA没有跳出循环,也就是说threadB对共享变量flag的更新操作对threadA不可见, 存在可见性问题。
思考:上面例子中为什么多线程对共享变量的操作存在可见性问题?
当flag有volatile修饰时,具有可见性,执行结果线程A可以跳循环
当flag没有volatile修饰时,但是在load()方法内的while()中输出打印语句,如:System.out.println("正在加载数据......")后,,执行结果线程A还是可以跳循环,原因是println()方法内有synchronized (this),具有可见性。
当flag没有volatile修饰时,但是在load()方法内的while()中加上内存屏障后,执行结果线程A也是可以跳循环,具有可见性。
- public class UnsafeFactory {
-
- /**
- * 获取 Unsafe 对象
- * @return
- */
- public static Unsafe getUnsafe() {
- try {
- Field field = Unsafe.class.getDeclaredField("