JAVA并发编程补充-线程可见性

定义一个类Visibility1包含两个变量

public class Visibility1 {
public static boolean ready;
public static int number;
}
自定义一个线程类,当Visibility1中的ready属性为false时进入循环打印number
public class ReaderThread extends Thread{

@Override
public void run() {
while (!Visibility1.ready){
Thread.yield();
System.out.println(Visibility1.number);
}
}
}
测试线程
public class TestThread1 {
public static void main(String[] args) {
new ReaderThread().start();
Visibility1.number = 42;
Visibility1.ready = true;
}
}
输出结果有三种:
0:这种情况是先进入了循环执行了一次输出;
42:这种情况是number被赋值42之后进入的循环;
空:这种情况是ready直接被赋值为true,没有进入循环;
这里涉及到一个指令排序的问题,例如:int a = 1; int b = 2; int c = a+b;这三条语句cpu有可能先执行第二条,但不会先执行第三条;(cpu的优化手段,有可能的第二条执行的时间比第一条短)。

这里写了一个测试类Visibility其中有一个bChanged变量,两个无限循环的线程,具体看注解,理论上说这个程序是会停止的,但是执行结果确实没有停止
public class Visibility {

private static boolean bChanged;

public static void main(String[] args) throws InterruptedException {

/**
* 第一个线程,当bChanged为true的时候输出 "!=" 然后退出java虚拟机
*/
new Thread(()-> {
for ( ; ; ) {
if (bChanged == true){
System.out.println("!=");
System.exit(0);
}
}
}).start();

/**
* 第二个线程,将本次、bChanged赋值为true
*/
Thread.sleep(10);
new Thread(()-> {
for (;;){
bChanged = true;
}
}).start();
}
}
原因如下图,由于cpu运行太快在cpu内存之间还有一层缓存,进入死循环没有退出是因为第一个线程的变量是读取的缓存。

解决方法:使用 volatile关键字:1保证变量的修改让所有线程可见;2阻止指令排序;

     volatile是比较古老的关键字   synchroized已经优化的很好了,不要去刻意的使用volatile

private static volatile boolean bChanged;

sync能够解决可见性、原子性 volatile只能解决               如果CAS操作没有原子化多线程操作一定会有问题  先比较在修改CAS操作    compare  and  set

线程并发问题:写或者读到了一个过期的数据,解决方式

1.线程封闭:final   不要线程之间共享变量      (约等于没用过)

2.栈封闭:比如说方法内部声明,修改  不会溢出,方法执行完就释放,不存在于内存

3.ThreadLocal线程绑定。

 

转载于:https://www.cnblogs.com/sleepy-goblin/p/9298020.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值