把java基础撸一边,从简单的开始。
java
线程部分:缓存
对synchronize初步了解以后,知道大概原理暂时先放下,其余深刻的后续再来(缘由是我也还不会)。本章是对java提供的另外一个关键字volatile认识一下,并使用它。bash
volatile 单词意思:adj. [化学] 挥发性的;不稳定的;爆炸性的;反复无常的
多线程
n. 挥发物;有翅的动物ide
我理解为是个可变的意思,不稳定。ui
在多线程开发中,对共享数据的操做是会有频繁操做的,为了保证在开发中,对会频繁变更的多线程操做数据保证一致性。java提供了synchronize,还有volatile。this
在了解以前,知道一个词:可见--一个线程修改了这个变量,在另外一个线程中可以读到这个修改后的值。这里注意一下,只是读到,而不是读写操做。不能保证原子性spa
synchronize是在保护他的代码块,不被同时两个线程进入操做出现,让线程是串行进入。重而保证了这个可见性。线程
volatile是怎么样保证参数的可见呢?code
这里直接讲原理会好点:在建立实例的时候,加了volatile修饰词的话,在汇编中会多了一个lock指令。
在多处理器的系统上,1:将当前处理器缓存行的内容写回都系统内存
2:这个写回内存的操做会使其余CPU里的缓存了该内存地址的数据失效
能够理解为volatile是读锁。在内存int a 的数据被线程1影响到了CPU线程2缓存的int i的数据,但注意。这里只相信读到的数据。但不影响线程2线程3这个共享内存的数据操做。这样也就能够知道,这个volatile的局限性。它不具有原子性,只有可见性。及时更新,但不限制其余数据退volition修饰的操做。
对于他的局限性。运行作以下操做
对一先修饰也volition的数据,程序只运行一方进行操做,其余线程不容许进行更改,只能够读。这也是叫轻量级锁的缘由。下面展现代码
public class A3 {
private volatile int a ;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
}复制代码
public class Demo31 {
public static void main(String[] age ){
A3 a3 = new A3();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0 ; i <= 100 ; i++){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "修改值"+i);
a3.setA(i);
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0 ; i <= 100 ; i++){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "读取值"+a3.getA());
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0 ; i <= 100 ; i++){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "读取值"+a3.getA());
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0 ; i <= 100 ; i++){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "读取值"+a3.getA());
}
}
}).start();
}
}复制代码
Thread-0修改值0
Thread-1读取值0
Thread-2读取值0
Thread-3读取值0
Thread-0修改值1
Thread-1读取值1
Thread-2读取值1
Thread-3读取值1
Thread-0修改值2
Thread-1读取值2
Thread-2读取值2
Thread-3读取值2
Thread-0修改值3
Thread-1读取值3
Thread-2读取值3
Thread-3读取值3
Thread-0修改值4
Thread-1读取值4
复制代码
能够看到,一旦线程被修改以后,读取到的数据就不会更改过来。但若是同时对数据进行修改
public class Demo31 extends Thread {
public volatile int a = 0 ;
public void set(){
for (int i = 0 ; i < 100 ; i++){
a++;
System.out.println(Thread.currentThread().getName() + " a : "+a);
}
}
@Override
public void run() {
set();
}
public static void main(String[] age ){
new Demo31().start();
new Demo31().start();
new Demo31().start();
}
}复制代码
结果
Thread-0 a : 1
Thread-1 a : 1
Thread-1 a : 2
Thread-0 a : 2
Thread-1 a : 3
Thread-2 a : 1
Thread-1 a : 4
复制代码
即便被volatile修饰以后,但并不会保证原子性。对于volatile的操做。要尽可能保证是一个线程修改,其余线程只是读。
推荐文章: