Synchronized atomic volatile

理解的很浅薄,用于临时抱佛脚,以后还是要好好看看

从Singleton说起

从Singleton说起,一般创建singleton的过程是这样的 ref: javarevisited blog

private static Singleton _instance; 

public static Singleton getInstance() 
{ 
  if (_instance == null) { 
      _instance = new Singleton(); 
  } 
  return _instance; 
}

以上的程序不是线程安全的,问题出现在create那部分,如果一旦已经创建,返回的都是instance,但是如果有两个thread同时调用一个没有创建过的instance,那么就会出现问题。

解决方法1: 用synchronized关键字,但是会非常大地降低效率

解决方法2:用volatile关键字,这样每一次thread调用instance的时候不在从自己的工作区域调,而是从memory里面读取,就不会再有问题了

private volatile static Singleton _instance;

这样既可。

补充一点,一个interview问题:如何保证一个实例不会被garbage collection掉?

答案:用Singleton, 拥有static reference是不满足gc的条件的,直到整个classloader被清理掉

volatile关键字

所以就说到了volatile关键字,volatile的意思就是,每一次读取的时候都必须从memory中读取,保证visibility,但是并不能保证“并发正确性”(concurrency正确性),不可以理解成原子操作。

比如两个线程共享一个cnt域,如果用了volatile, 读取的时候都是正确的,但是写回的时候可能就会发生问题。

synchronized

分为两种,一种在method上就加synchronized,一种是synchronized block,如果用synchronized那么是相当于对这个object同步,那么所有带synchronized的地方都要等着,如果对于一个field synchronize,只有对同一个field的地方才会等。

举个🌰


public class MyCounter implements Runnable {
    private static int counter = 0;
    private static int num = 0;

    public void run() {
      System.out.println(counterAddOne);
    System.out.println(numAddOne);

    private synchronized void counterAddOne() {
        counter++;
    }

    private synchronized void numAddOne() {
        num++;
    }
  }
}

public class Test {
  public static void main(String[] args) {
    MyCounter myCounter = new MyCounter();
      Thread t1 = new Thread(myCounter);
    Thread t2 = new Thread(myCounter);
    t1.start();
    t2.start();
  }
}

如果是以上这样,一起就连counter带num就都锁了,但是


public class synchronized MyCounter implements Runnable {
    private static int counter = 0;
    private static int num = 0;
    private Object countLock = null;
    private Object numLock = null;

    public void run() {
      System.out.println(counterAddOne);
    System.out.println(numAddOne);

    private void counterAddOne() {
        synchronized(counterLock) {
          counter++;
        }
    }

    private void numAddOne() {
        synchronized(numCounter) {
          num++;
        }
    }
  }
}

以上,counter和num就可以分开被锁上啦

results matching ""

    No results matching ""