volatile关键字

  • 主要作用:使变量在多个线程间可见
  • 主要的两种特性:
    • 变量可见性:
      • JDK1.5之后,线程运行时,会创建一个工作区,方便线程运行,此时会拷贝一份主工作区的变量到线程的工作区中,每次修改,对其他线程是不可见的。使用volatile关键字可以保证主工作区的变量的更新会同步到各个线程区中去(可见性),volatile关键字会强制线程的执行引擎去主工作区中去取,保证了数据的一致性
    • 禁止重排序:
  • 与sychronized区别
    • 比 sychronized 更轻量级的同步锁
      • 在访问volatile变量时不会进行加锁操作,因此不会出现线程阻塞,性能会高于sychronized,但是不能替代sychronized的位置
    • 适用场景的限制
      • volatile关键字单次读/写操作下才具备原子性,所以对变量的写操作不依赖于当前值才能使用volatile(i++)不行,i++是读和写的操作
      • 不同的volatile变量之间不能互相依赖
    • volatile能保证数据的可见性,但不能完全保证数据的原子性,synchronized即保证了数据的可见性也保证了原子性
public class Demo1_Volatile extends Thread { //volatile的使用位置 private volatile boolean isRunning = true; public void setValue(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 { Demo1_Volatile thread = new Demo1_Volatile(); //创建一个线程实例 thread.start(); //启动线程 Thread.sleep(3000); thread.setValue(false); System.out.println("isRunning的值已经被修改成false"); Thread.sleep(3000); System.out.println(thread.isRunning); } } //不使用volatile时,虽然已经修改为了false,由于前面所说的变量的不可见性,线程里并不知道isRunning值已经修改了,此时线程还在死循环中 进入到了run方法
isRunning的值已经被修改成false false //使用volatile时,isRunning修改时,线程立即就看到了更新, 并取过来使用,线程结束 进入到了run方法
isRunning的值已经被修改成false 线程停止 false 

sychronized关键字

  • sychronized锁重入
    • 当一个线程得到一个对象锁后,再次请求此对象锁时,是可以再次得到该对象的锁的。也就是说在一个synchronized方法或块的内部调用本类的其他synchronized方法或块时,是永远可以得到锁的
  • 使用场景
    • 对对象加锁,进入同步代码前要获得给定对象的锁
    • 直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁
    • 直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁
//作用在对象上 public class ThreadSync implements Runnable { static ThreadSync instance=new ThreadSync(); static int count=0; @Override public void run() { // TODO Auto-generated method stub for (int i = 0; i < 10000000; i++) { synchronized (instance) { //作用在对象上 count++; } } } public static void main(String[] args) throws InterruptedException { // TODO Auto-generated method stub Thread t1=new Thread(instance); Thread t2=new Thread(instance); t1.start(); t2.start(); t1.join(); //让线程执行结束 t2.join(); //让线程执行结束 System.out.println(count); } } //作用在实例方法上 public class ThreadSync2 implements Runnable { static ThreadSync2 instance=new ThreadSync2(); static int count=0; public synchronized void add() { //作用在实例方法上 count++; } @Override public void run() { // TODO Auto-generated method stub for (int i = 0; i < 10000000; i++) { add(); } } public static void main(String[] args) throws InterruptedException { // TODO Auto-generated method stub Thread t1=new Thread(instance); Thread t2=new Thread(instance); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(count); } } //作用在静态方法上 public class ThreadSync3 implements Runnable { static int count=0; public static void add() { count++; } @Override public void run() { // TODO Auto-generated method stub for (int i = 0; i < 10000000; i++) { add(); } } public static void main(String[] args) throws InterruptedException { // TODO Auto-generated method stub Thread t1=new Thread(new ThreadSync3());//创建两个不同的对象 Thread t2=new Thread(new ThreadSync3()); t1.start(); t2.start(); t1.join(); t2.join(); } }