北京怎样建设公司网站,成都手机微信网站建设报价单,怎么样自己做网站接订单,西安搬家公司电话号码大全一、什么是可见性#xff1f; 可见性问题是基于CPU位置出现的#xff0c;cpu处里速度非常快#xff0c;相对CPU来说去主内存 获取数据这个事情太慢了#xff0c;CPU就提供了 L1#xff0c;L2#xff0c;L3的三季缓存#xff0c;每次去主内存拿完 数据后#xff0c;数据…一、什么是可见性 可见性问题是基于CPU位置出现的cpu处里速度非常快相对CPU来说去主内存 获取数据这个事情太慢了CPU就提供了 L1L2L3的三季缓存每次去主内存拿完 数据后数据就先存储到三级缓存然后cpu再去三级缓存取数据效率肯定会提升 三级缓存就是是每个线程的工作内存是相互独立的。 这就带来了一个问题现在CPU都是多核每个线程的工作内存CPU三级缓存都 是独立的会告知每个线程做修改时只修改自己的工作内存数据没有及时同步到主内存 从而导致数据不一致的问题 线程运行时数据处里过程如下 使用下边代码来验证数据可见性的问题代码如下 二、解决可见性问题的方式 1、volatile volatile是一个关键字用于修饰成员变量 如果属性被volatile修饰相当于告诉cpu对于当前属性的操作不允许使用CPU 缓存即线程私有内存必须去操作主内存。 volatile的内存语义 1volatile 属性被写当写一个volatile变量JMM会将当前线程的CPU缓存的 数据及时刷新到主内存中 2volatile 属性被读当读一个volatile变量JMM会将当前线程对应的CPU缓存 设置为无效必须从主内存读取数据。 其实变量加了volatile就是告诉cpu对当前变量的读写操作不允许使用CPU缓存加 了volatile 的变量会在编译成汇编之后追加一个lock前缀CPU执行这个指令时如果 带有lock前缀会做2件事 1将当处理器缓存行的数据写回到主内存 2这个写会的数据在其他的CPU内核的缓存中直接无效 总结volatile 就是让CPU每次操作这个数据时必须立即同步到主内存以及从主内 存读取数据。 在代码中若先对volatile属性进行操作则其他属性也是可见性的。 针对上边的代码采用volatile解决可见性问题实现如下
/******************************************************** 验证线程的可见性问题* 每个线程都有自己的私有内存相互独立线程运行时处里的是自己私有内存的数据** 使用volatile解决内存可见性*******************************************************/
public class Test02 {private volatile static boolean flag true;public static void main(String[] args) throws InterruptedException {Thread t1 new Thread(() - {while (flag){}System.out.println(子线程 t1 中 flag改变);});t1.start();//预期flag修改成false后,不影响线程t1的运行Thread.sleep(100);//修改flag 的值flag false;System.out.println( main 线程中修改 flag false);}
}//方案二在代码中若先对volatile属性进行操作则其他属性也是可见性的
public class Test02 {private volatile static int i 0;private static boolean flag true;public static void main(String[] args) throws InterruptedException {Thread t1 new Thread(() - {while (flag){//todo: 在代码中若先对volatile属性进行操作则其他属性也是可见性的i;}System.out.println(子线程 t1 中 flag改变);});t1.start();//预期flag修改成false后,不影响线程t1的运行Thread.sleep(100);//修改flag 的值flag false;System.out.println( main 线程中修改 flag false);}
}2、synchronized synchronized也是可以解决可见性问题。 synchronized内存语义 如果涉及到了synchronized 的同步代码块或者同步方法获取资源之后将内部 涉及到的变量从CPU缓存线程私有内存中移除必须重新去主内存中取数据 而且在释放锁之后会立即将CPU缓存中的数据同步到主内存中。 使用 synchronized 解决内存可见性 示例代码如下 /******************************************************** 验证线程的可见性问题* 每个线程都有自己的私有内存相互独立线程运行时处里的是自己私有内存的数据** 使用synchronized解决内存可见性*******************************************************/
public class Test03 {private static boolean flag true;public static void main(String[] args) throws InterruptedException {Thread t1 new Thread(() - {while (flag){/** 问题为什么这里synchronized 放在while循环里边不放在外边* 因为线程 在获取到 synchronized 锁之后才会从主内存拿数据若把synchronized 放在while外边* 则只会从主内存拿一次数据后边不能监听到变量 flag 变化*/synchronized (Test03.class){//todo}}System.out.println(子线程 t1 中 flag改变);});t1.start();//预期flag修改成false后,不影响线程t1的运行Thread.sleep(100);//修改flag 的值flag false;System.out.println( main 线程中修改 flag false);}
}3、Lock Lock锁保证可见性的方式和synchronized 完全不同synchronized是基于内存语义在获取 锁和释放锁对CPU缓存做一个同步到主内存的操作。 lock 锁是基于volatile实现的lock 锁内部进行加锁和释放锁时会对一个volatile修饰的属 state做加减操作。 如果对volatile属性进行写操作CPU会执行带有lock前缀的指令会将CPU缓存的数据立 即同步到主内存同时也会将其他非volatile属性页一起同步到主内存。还会将其他CPU缓 存行 中这个volatile数据设置为无效必须从主内存重新拉取。 lock解决可见性示例代码如下 /******************************************************** 验证线程的可见性问题* 每个线程都有自己的私有内存相互独立线程运行时处里的是自己私有内存的数据** 使用lock解决内存可见性*******************************************************/
public class Test04 {private static boolean flag true;private static ReentrantLock lock new ReentrantLock();public static void main(String[] args) throws InterruptedException {Thread t1 new Thread(() - {while (flag){lock.lock();try {//。。。。。}finally {lock.unlock();}}System.out.println(子线程 t1 中 flag改变);});t1.start();//预期flag修改成false后,不影响线程t1的运行Thread.sleep(100);//修改flag 的值flag false;System.out.println( main 线程中修改 flag false);}
}4、final final本质上说并不能像synchronized和volatile 那种形式保证可见性final修饰的属性在 运行期间是不允许修改的这样一来就间接保证了可见性。 final与volatile不允许同时修饰一个属性final修饰的属性不允许被修改而volatile保证 每次从主内存读取数据并且volatile会影响一定性能就不需要同时修饰。 final与volatile同时修饰属性会报错如下图所示