并发编程三大特性
所谓并发编程是指在一台处理器上“同时”处理多个任务。并发是在同一实体上的多个事件。多个事件在同一时间间隔发生。
可见性(visibility)
有序性 (ordering)
原子性(atomicity)
可见性:
首先看一个小程序
public class T01 {
private static boolean running = true;
private static void m(){
System.out.println("m start");
while (running){
System.out.println("hello");
}
System.out.println("m end!");
}
public static void main(String[] args) {
new Thread(T01::m,"t1").start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
running = false;
}
}
结果就是只有m start输出 一直没有后面的东西了
因为running 的值是被copy了一份到另一个线程 在缓存里 如果这个线程不重新读取 他就会一直是true
你只是修改了主线程的running 而没有修改另一个线程的running 一个线程基本上看不到另一个线程的值
这时候怎么办呢?只有把runnig值加关键字volatile修饰才可以
volatile: 保持线程的可见性
对于他任意的修改
被volatile修饰的内存都会去主内存读取一次
所以变成下面
public class T01 {
private static volatile boolean running = true;
private static void m(){
System.out.println("m start");
while (running){
// System.out.println("hello");
}
System.out.println("m end!");
}
public static void main(String[] args) {
new Thread(T01::m,"t1").start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
running = false;
}
}
但是有人会发现 在里面加了一个sout 输出一个hello 本来应该是一直持续下去的 但是却执行了一会儿 就结束了进程
/**
* Prints a String and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(String)}</code> and then
* <code>{@link #println()}</code>.
*
* @param x The <code>String</code> to be printed.
*/
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
那是因为println方法的底层是一个锁 也可以理解为保证了可见性
所以有些语句 (指令)是可以触发本地线程缓存和主线程之间的一个刷新和同步 但是这些都不是不可用的方法 上锁也意味着效率变低 所以该加volatile 就用 volatile
volatile 引用类型(包括数组)只能保证引用本身的可见性,不能保证内部字段的可见性