三大特性分别是原子性 ,可见性,有序性
原子性:指一个操作是不可中断的,即使是多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰
可见性:指当一个线程修改了某一个共享变量的值,其他线程是否能够立即知道这个修改。显然,对于串行程序来说,可见性问题 是不存在。因为你在任何一个操作步骤中修改某个变量,那么在后续的步骤中,读取这个变量的值,一定是修改后的新值。但是这个问题在并行程序中就不见得了。如果一个线程修改了某一个全局变量,那么其他线程未必可以马上知道这个改动。
有序性:对于一个线程的执行代码而言,我们总是习惯地认为代码的执行时从先往后,依次执行的。这样的理解也不能说完全错误,因为就一个线程而言,确实会这样。但是在并发时,程序的执行可能就会出现乱序。给人直观的感觉就是:写在前面的代码,会在后面执行。有序性问题的原因是因为程序在执行时,可能会进行指令重排,重排后的指令与原指令的顺序未必一致。
分析代码:(这段代码的执行结果总是小于等于10000)
public static volatile int num = 0;
public static void main(String[] args) {
Thread[] thread = new Thread[10];
for (int i = 0; i < thread.length; i++) {
thread[i] = new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 1000; j++) {
add();
}
}
});
thread[i].start();
}
System.out.println(num);
}
public static void add() {
num++;
}
解释如图:(解释如上的代码)
public static volatile int x = 0, y = 0;
public static void main(String[] args) throws InterruptedException {
x=0;
y=0;
Set<String> set = new HashSet<>();
Map<String, Integer> map = new HashMap<>();
map.clear();
for (int i = 0; i < 1000; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
int a = y;
x = 1;
map.put("a", a);
}
});
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
int b = x;
y = 1;
map.put("b", b);
}
});
thread.start();
thread1.start();
thread.join();
thread1.join();
set.add("a=" + map.get("a") + "," + "b=" + map.get("b"));
System.out.println(set);
}
}
接着分析一下这段代码:居然会出现a=1,b=1的情况
当a=1时,说明y=1
此时说明线程二先执行完了int b=x(此时x应该等于零才对)。
怎么会出现这种情况???????????
有序性问题的原因是因为程序在执行时,可能会进行指令重排,重排后的指令与原指令的顺序未必一致