天天看点

java关键词Transient、native、volatile

Transient是出现在mybatis映射实体类的时候,实体类某属性不需要映射的数据库表字段的时候加上@transient标签。主要的作用是对象序列化的时候会忽略这个属性。

native在看法的过程没有使用过,在看源码的时候经常看到过用它来修饰一些方法。主要的作用在方法前加上native,代表方法是通过外部底层C实现的,调用的时候会用调用C语言方法调用。

volatile使用是在多线程开发的时候,有共享变量,使用它来就行修饰变量,注意它不能保证变量的原子性。对于读操作时:该变量拿到的一直是主内存的(最新值),主要是在多线程共享变量中,某一个线程更改变量,另一个线程有可能会从缓存中读取(优化的问题),用它可以保证变量的可见性;对于写操作时:将当前处理器缓存行的数据写回到系统内存, 这个写回内存的操作会使得在其他处理器缓存了该内存地址无效。

为什么volatile不能保持原子性:当两个线程同时操作自增的时候,取值、加值、改变内存值,由于取值跟加值都是同一个时间点,两者都还未提交修改值,内存值没有失效,然后同时提交。

添加一段代码验证volatile的可见性:

public class Test implements Runnable {


    /**
     * 内部类实现static
     */
    static class ObjectA {
        private boolean flag = true;
    }

    /**
     * 尝试不用volatile修饰变量和用volatile修饰变量的区别
     */
    private  volatile ObjectA a;


    /**
     * 构造函数
     * @param a
     */
    public Test(ObjectA a) {
        this.a = a;
    }

    /**
     * 实现线程run
     */
    @Override
    public void run() {
        while (a.flag) {
            //不做任何操作,或者极短的操作时间
        }
    }

    /**
     * 改变变量a的值,让线程停止的功能
     */
    public void stop() {
        a.flag = false;
    }

    public static void main(String[] args) throws InterruptedException {
        //启动线程
        Test test = new Test(new ObjectA());
        Thread t = new Thread(test);
        t.start();

        //跑一段时间
        Thread.sleep(1000);
        //停止线程
        test.stop();
        //等待子线程停止
        t.join();

    }

}
           

整个代码逻辑是启动一个线程,运行1秒,关闭它,当我们用volatile修饰a变量的时候,代码是没问题的,当变量改变的时候,线程马上停止;如果不用volatile修饰变量a,会发现线程一直在运行,a变量明明改变值了,但是run获取到的值一直是旧的值。