多线程的三个特性
多线程要保证并发线程正确执行,必须要保证三个特性。
1 原子性(互斥性):
- 一个或多个操作不能被分割,要么全部执行,要么就都不执行。
2 可见性:
- 多个线程访问同一个变量,一个线程修改了这个变量,别的线程能立即看到修改的值。
- volatile关键字保证内存可见性。
3 有序性:
- 程序执行的顺序按照代码的先后顺序执行。
- 在单线程中处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证程序中各个语句的执行顺序和编写顺序一致,但最终结果是一致的。但是多线程可能会有问题。
- volatile保证有序性(禁止指令重排序)。
三个特性的实现
synchronized可保证原子性和可见性。但不能保证有序性。
volatile可保证可见性和有序性。但不能保证原子性。
volatile 关键字配合 synchronized 或 Lock接口 实现了原子性、可见性、有序性。
eg:
volatile: 不稳定, 易挥发的 (解除子线程缓存)
public class TestVolatile {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
System.out.println("输入任意字符结束子线程");
Scanner input = new Scanner(System.in);
input.next();
myThread.flag = true;
System.out.println("flag: "+myThread.flag);
}
static class MyThread extends Thread {
volatile boolean flag = false;
@Override
public void run() {
System.out.println("子线程开始执行...");
while (true) {
if (flag) {
break;
}
}
System.out.println("子线程结束了...");
}
}
}
内存分析:
面试题
i++是原子操作吗? 不是原子操作。
(1)读取i的值 (2)执行加1操作(3)修改i的值
使用原子操作类解决。
TestAtomic:
public class TestAtomic {
public static void main(String[] args) {
Atomic atomic = new Atomic();
ExecutorService es = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
es.submit(()-> System.out.println(atomic.getNum()));
}
es.shutdown();
}
static class Atomic {
// private int num = 0;
private final AtomicInteger integer = new AtomicInteger();
public int getNum() {
return integer.getAndIncrement();
}
}
}