volatile:使变量在多个线程中可见
在java 中每个线程都会有一块工作内存区,其中存放着所有线程共享的主内存中变量的拷贝。当线程执行时,在自己的工作内存区操作这些变量,为了存取一个共享的变量,
一个线程通常先获取锁定并去清除它的内存工作区,把这些共享变量从所有线程的共享内存中正确的装入到他自己所在的工作内存区中,
当线程解锁时,保证该工作内存中变量的值写回到共享内存中。
一个线程可以执行的操作有使用(use)、赋值(assign)、装载 (load)、存储(store) 锁定(lock) 解锁(unloack)
主内存可以执行的操作有读(read) 写(write) 锁定(lock) 解锁(unlock) 每个操作都是原子的
public class RunThread extends Thread{ private volatile boolean isRunning = true; private void setRunning(boolean isRunning){ this.isRunning = isRunning; } public void run(){ System.out.println("进入run方法.."); int i = 0; 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"); } }
volatile关键字虽然拥有多个线程之间的可见性,但不具备同步性,算一个轻量级的synchronized,性能要比synchronized强很多,不会造成阻塞。
一般用于针对多个线程可见的变量操作,并不能代替synchronized的同步功能。
volatile关键字只有可见性,没有原子性,要实现原子性使用atomic类的系列对象,支持原子性操作,atomic类只保证方法原子性,并不保证多次操作的原子性
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(); } } }
import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.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() { @Override public void run() { System.out.println(au.multiAdd()); } })); } for(Thread t : ts){ t.start(); } } }
Volatile称之为轻量级锁,被volatile修饰的变量,在线程之间是可见的,保证不了操作的原子性
可见:一个线程修改了这个变量的值,在另一个线程中能够读取到这个修改的值
Synchronized:除了线程之间的互斥意外,还有一个非常的大的作用,就是保证可见性
//保证可见性的前提 //多个线程拿到的是同一把锁,否则是保证不了的 public class Demo { public volatile int a=1; public static void main(String[] args) { Demo demo=new Demo(); demo.a=10; new Thread(new Runnable() { @Override public void run() { System.out.println(demo.a); } }).start(); System.out.println("最终的结果为:"+demo.a); } }
public class Demo2 { public volatile boolean run =false; public static void main(String[] args) { Demo2 d=new Demo2(); new Thread(new Runnable() { @Override public void run() { for(int i=1;i<=10;i++){ System.out.println("执行了第"+i+"次"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } d.run=true; } }).start(); new Thread(new Runnable() { @Override public void run() { while(!d.run){ //不执行 } System.err.println("线程2执行了"); } }).start(); } }
lock指令:
在多处理器的系统上
将当前处理器缓存行的内容写回到系统内存,
写回到内存操作会使在其他CPU里缓存了该内存地址的数据失效