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就可以分开被锁上啦