JAVA JUC volatile 关键字
1 内存可见性问题
class flagTest implements Runnable{ private boolean flag = false; @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } flag=true; System.out.println("flag="+flag); } public boolean getFlag(){ return flag; } } public class volatileTest { public static void main(String[] args) { flagTest ft = new flagTest(); Thread thread = new Thread(ft); thread.start(); while (true){ if(ft.getFlag()) System.out.println("----------"); } }
如上的程序,主线程会一直在while里面死循环. 这是因为,java程序在主内存里创建了一个flag=false.线程1和主线程读取flag的时候,分别复制了一份.当线程1对flag的值进行修改之后,由于主线程存在flag的副本,且while(true)效率极高,所以没有刷新flag的值,导致主线程陷入死循环.这就是共享变量的内存不可见问题.
要解决这个问题,可以使用synchronized加锁,这样在访问共享变量的时候,就会刷新内存变量.但是弊端是,程序执行效率大幅度下降.
public class volatileTest { public static void main(String[] args) { flagTest ft = new flagTest(); Thread thread = new Thread(ft); thread.start(); while (true){ synchronized (ft){ if(ft.getFlag()) { System.out.println("----------"); break; } } } }
使用volatile关键字,可是使得共享变量的内存可见性提高,可以理解为不同的线程直接在主内存里面访问共享变量.
class flagTest implements Runnable{ private volatile boolean flag = false; @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } flag=true; System.out.println("flag="+flag); } public boolean getFlag(){ return flag; } } public class volatileTest { public static void main(String[] args) { flagTest ft = new flagTest(); Thread thread = new Thread(ft); thread.start(); while (true){ if(ft.getFlag()) { System.out.println("----------"); break; } } }
private volatile boolean flag = false;
volatile具有以下特点:
当线程之间进行数据共享时,使用volatile关键字修饰,可以使得共享变量内存可见,相比与synchronized,它是一种轻量级的线程锁.
1 不具有互斥性
2 不能保证变量的原子性.