JUC多线程及高并发3-----volatile

23 篇文章 0 订阅
13 篇文章 0 订阅

你的同学在学习,你的对手在磨刀,你的闺蜜在减肥,你还等什么?

 

JMM-----原子性代码证明(面试题笔记3)

 

package jMM;

import java.util.concurrent.TimeUnit;

//1.
public  class Jmm_kejianxing {
    volatile int number =0;   //原主机的数据
    public  void  addT060(){
        this.number =60;   //之后数据改变为60
    }

    //请注意,此时的number前面是加了volatile,所以不保证原子性
    public void addPlusPlus(){
        number++;
    }
}
/*
* 1.验证volatile的可见性
*  1.1 假如 int number =0 ;number变量之前根本没有添加volatile关键字修饰
*  1.2 添加了volatile,拥有了可见性
*
* 2.验证volatile不保证原子性
*   2.1原子性指的是什么意思?
*       不可分割,完整性,也即某个线程正在做某个具体业务时,中间不可以被加塞或者被分割。需要整体完整
*       要么同时成功,要么同时失败。
*
*   2.2不保证原子性案例演示
* */
class   VolatileDemo{
    public static void main(String[] args) //main方法是一切方法的运行入口
    {
        Jmm_kejianxing jmm_kejianxing =new Jmm_kejianxing();//资源类

//俩个实现多线程方法---1.实现Runnable接口,2.继承Thread类
//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//
//            }
//        }).start();
        new Thread(
                () -> {
           System.out.println(Thread.currentThread().getName()+"\t come in");
           //暂停一会儿线程
           try {TimeUnit.SECONDS.sleep(3);}catch (InterruptedException e){e.printStackTrace();}
                    jmm_kejianxing.addT060();
            System.out.println(Thread.currentThread().getName()+"\t update number value"+jmm_kejianxing.number);

           },"AAA").start();
    //第二个线程就是我们的main线程
    while (jmm_kejianxing.number == 0){
        //main 线程就一直再这里等待循环,直到number值不再等于0
    }
        System.out.println(Thread.currentThread().getName()+"\t mission is over");
    }
    }

 class VolatileDemo1{
        public static void main(String[] args) {
            Jmm_kejianxing jmm_kejianxing = new Jmm_kejianxing();
            for (int i = 1; i < 20; i++) {
                new Thread(() -> {
                    for (int j = 1; j <= 1000; j++) {
                        jmm_kejianxing.addPlusPlus();
                    }
                }, String.valueOf(i)).start();
            }
            //需要等待上面20个线程都全部计算完成后,再用main线程取得最终结果值是多少?
//            //暂停 一会儿线程
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            while(Thread.activeCount()>2){
                Thread.yield();}
            System.out.println(Thread.currentThread().getName()+"\t finally number value:"+ jmm_kejianxing.number);
        }
//volatile可以保证可见性,及时通知其他线程,主物理内存的值已经被修改
        public static void seeokByVolatile()
        {
            Jmm_kejianxing jmm_kejianxing = new Jmm_kejianxing();//资源类

            new Thread(
                    () -> {
                        System.out.println(Thread.currentThread().getName() + "\t come in");
                        //暂停一会儿线程
                        try {
                            TimeUnit.SECONDS.sleep(3);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        jmm_kejianxing.addT060();
                        System.out.println(Thread.currentThread().getName() + "\t update number value" + jmm_kejianxing.number);

                    }, "AAA").start();
            //第二个线程就是我们的main线程
            while (jmm_kejianxing.number == 0) {
                //main 线程就一直再这里等待循环,直到number值不再等于0
            }
            System.out.println(Thread.currentThread().getName() + "\t mission is over");
        }
    }

 

main	 finally number value:17966

Process finished with exit code 0

详细解释:   

   number++在多线程下是非线程安全的,所以结果并不是20000,加synchronized,----可以解决,但是有点大材小用了。
   因为volatile是轻量级,所以不保证原子性,所以数值小于20000,出现数据丢失现象。
(虽然每个线程都具备了可见性,但是由于速度快,导致数据被第一个线程写入,输出。当第二个线程接收到改变的数据时,输出时,会被第一个线程覆盖掉。)
   idea Java集成命令,需要配置,(左击Extenal TOOLS-》Javap -c)

深度学习Java字节码:

class Jmm_kejianxing {
 volatile int number =0;
 public void add(){
        number++;
    }
}

aload 0 ---------从局部变量0中装载引用类型值
dup  -------------部一个字长内容

 

n++步骤:
1.n=0初始值对应getfield 
2.iconst——1----n++要加一层
  iadd
3.putfield---写回主内存

 

方法二解决不保证原子性:

public  class Jmm_kejianxing {
    volatile int number =0;   //原主机的数据
    public  void  addT060(){
        this.number =60;   //之后数据改变为60
    }

    //请注意,此时的number前面是加了volatile,所以不保证原子性
    public void addPlusPlus(){
        number++;
    }
    AtomicInteger atomicInteger =new AtomicInteger();
    public void addAtomic(){
        atomicInteger.getAndIncrement();
    }
}

 

.验证volatile的可见性
*  1.1 假如 int number =0 ;number变量之前根本没有添加volatile关键字修饰
*  1.2 添加了volatile,拥有了可见性
*
* 2.验证volatile不保证原子性
*   2.1原子性指的是什么意思?
*       不可分割,完整性,也即某个线程正在做某个具体业务时,中间不可以被加塞或者被分割。需要整体完整
*       要么同时成功,要么同时失败。
*
*   2.2不保证原子性案例演示
*
*   2.3如何解决与原子性?
*      1,加synchronized
*      2,使用我们的juc下AtomicInteger
 class VolatileDemo1{
        public static void main(String[] args) {
            Jmm_kejianxing jmm_kejianxing = new Jmm_kejianxing();
            for (int i = 1; i <= 20; i++) {
                new Thread(() -> {
                    for (int j = 1; j <= 1000; j++) {
                        jmm_kejianxing.addPlusPlus();
                        jmm_kejianxing.addAtomic();
                    }
                }, String.valueOf(i)).start();
            }
            //需要等待上面20个线程都全部计算完成后,再用main线程取得最终结果值是多少?
//            //暂停 一会儿线程
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            while(Thread.activeCount()>2){
                Thread.yield();}
            System.out.println(Thread.currentThread().getName()+"\t int type finally number value:"+ jmm_kejianxing.number);
            System.out.println(Thread.currentThread().getName()+"\t AtomicInteger type,finally number value:"+ jmm_kejianxing.atomicInteger);
        }
//volatile可以保证可见性,及时通知其他线程,主物理内存的值已经被修改
        public static void seeokByVolatile()
        {
            Jmm_kejianxing jmm_kejianxing = new Jmm_kejianxing();//资源类

            new Thread(
                    () -> {
                        System.out.println(Thread.currentThread().getName() + "\t come in");
                        //暂停一会儿线程
                        try {
                            TimeUnit.SECONDS.sleep(3);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        jmm_kejianxing.addT060();
                        System.out.println(Thread.currentThread().getName() + "\t update number value" + jmm_kejianxing.number);

                    }, "AAA").start();
            //第二个线程就是我们的main线程
            while (jmm_kejianxing.number == 0) {
                //main 线程就一直再这里等待循环,直到number值不再等于0
            }
            System.out.println(Thread.currentThread().getName() + "\t mission is over");
        }
    }

结果: 

main	 int type finally number value:19097
main	 AtomicInteger type,finally number value:20000

Process finished with exit code 0

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值