volatile关键字
先看下面的代码:
public class RunThread extends Thread{ private boolean isRunning = true; private void setRunning(boolean isRunning){ this.isRunning = isRunning; } public void run(){ System.out.println("进入run方法.."); while(isRunning == true){ //.. } System.out.println("线程停止"); } public static void main(String[] args) throws InterruptedException { RunThread rt = new RunThread(); rt.start(); Thread.sleep(1000); rt.setRunning(false); System.out.println("isRunning的值已经被设置了false"); } }
执行代码,会发现这个程序一直会运行,而不会停止。
因为在主线程中创建了rt对象,并且调用了run方法,启动了另一个线程,这个线程会复制isRunnning变量的副本到工作内存空间。
所以当主线程对rt对象的属性isRunning做了更改时,对其他线程而言是无效的,因为其他的线程都有自己的副本,读取的也是副本中的内容。
改变上述状况的方法是使用volatile关键字,isRunning属性要使用volatile关键字进行修饰。
volatile不具备synchronized关键字的原子性(同步)
/** * volatile关键字不具备synchronized关键字的原子性(同步) * */ public class VolatileNoAtomic extends Thread{ //private static volatile int count; private static AtomicInteger count = new AtomicInteger(0); private static void addCount(){ for (int i = 0; i < 1000; i++) { //count++ ; count.incrementAndGet(); } System.out.println(count); } public void run(){ addCount(); } public static void main(String[] args) { VolatileNoAtomic[] arr = new VolatileNoAtomic[100]; for (int i = 0; i < 10; i++) { arr[i] = new VolatileNoAtomic(); } for (int i = 0; i < 10; i++) { arr[i].start(); } } }
AtomicInteger的方法是原子性的,但是在一个方法里多个方法不是原子的
public class AtomicUse { private static AtomicInteger count = new AtomicInteger(0); //多个addAndGet在一个方法内是非原子性的,需要加synchronized进行修饰,保证4个addAndGet整体原子性 /**synchronized*/ public synchronized int multiAdd(){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } count.addAndGet(1); count.addAndGet(2); count.addAndGet(3); count.addAndGet(4); //+10 return count.get(); } public static void main(String[] args) { final AtomicUse au = new AtomicUse(); List<Thread> ts = new ArrayList<Thread>(); for (int i = 0; i < 100; i++) { ts.add(new Thread(new Runnable() { public void run() { System.out.println(au.multiAdd()); } })); } for(Thread t : ts){ t.start(); } } }