1:为什么要引入AtomicInteger关键字
在java中,多个线程访问一个共享变量时会发生线程安全问题。
例子:
Count类:
主函数开三个线程:
我们希望count的值为599,但是由于是多线程,所以结果如下:
那么我们应该怎么处理呢?
java为我们引入了一个包(atomic)来处理该情况。
代码如下:
count类:
结果如下:
AtomicInteger关键字能保证变量值得准确性,但不能保证它们能按顺序输出。但一般我们都只是获取它的值,而不是打印它的值。
如果你既想保证数字的准确性又想保证能按顺序输出,你只能用Synchronized关键字了
代码如下:
总结: synchronized关键字是一种内部锁,可以理解成一个小黑屋,每个线程走到被synchronized代码块包含的代码就像进入这个小黑屋,只能一个一个的操作。
2:volatile关键字
被volatile修饰的变量,在多个线程下是可见的,其作用是让该变量在多哥线程下是透明的(让程序从内存中加载,不允许在缓存中加载)。可以保证变量的修改让所有线程可见;
代码:
按我们所想,就俩线程不过怎么着,程序总会停止吧。但是,程序死在这里了。如图
为什么会这样?
因为线程是CPU启动的,而CPU一开始从主存中取数据并没有立即将数据送到CPU,而是先送到了缓存中, 另外一个线程修改bChanged的值,是就该主存中的值,而那个输出结果的线程并没有从主存中取bChanged的值,而是去缓存中取了bChanged的值,而缓存中bChanged的值是false,这就是为什么会死循环的原因。如下图
这个时候,java提供的volatile关键字就派上了用处。它保证了变量在线程之间的可见性。让程序不要去缓存中取值,而是去主存中取值。
你会发现加上volatile关键字后,程序会秒停。
3:可重入锁
一个线程获取它本身的锁是可以成功的,多个线程同时抢占同一个锁会失败。因为他们之间是互斥的。但是一个线程再次获取一个自己已经拿过的锁是可以成功的,这叫可重入锁机制 。