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获取到的值一直是旧的值。