package thread;
class Counter {
// 这个 变量 就是两个线程要去自增的变量
public int count;
public void increase() {
count++;
}
}
public class Demo15 {
private static Counter counter = new Counter();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 50000; i++) {
counter.increase();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 50000; i++) {
counter.increase();
}
});
t1.start();
t2.start();
// 必须要在 t1 和 t2 都执行完了之后, 在打印 count 的结果.
// 否则, main 和 t1 t2 之间都是并发的关系~~, 导致 t1 和 t2 还没执行完, 就先执行了下面的 打印 操作
t1.join();
t2.join();
// 在 main 中打印一下两个线程自增完成之后, 得到的 count 结果~~
System.out.println(counter.count);
}
}
package thread;
class Counter {
// 这个 变量 就是两个线程要去自增的变量
public int count;
public void increase() {
synchronized (this) {
count++;
}
}
}
public class Demo15 {
private static Counter counter = new Counter();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 50000; i++) {
counter.increase();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 50000; i++) {
counter.increase();
}
});
t1.start();
t2.start();
// 必须要在 t1 和 t2 都执行完了之后, 在打印 count 的结果.
// 否则, main 和 t1 t2 之间都是并发的关系~~, 导致 t1 和 t2 还没执行完, 就先执行了下面的 打印 操作
t1.join();
t2.join();
// 在 main 中打印一下两个线程自增完成之后, 得到的 count 结果~~
System.out.println(counter.count);
}
}
1.线程是抢占式执行2.多个线程对同一个变量进行修改操作3.针对变量的操作不是原子的4.内存可见性问题5.指令重新排序
不保证原子性会给多线程带来什么问题?
如果一个线程正在对一个变量操作,中途其他线程插入进来了,如果这个操作被打断了,结果就可能是错误的。
可以从硬件角度(CPU,内存)回答;也可从JMM角度(主内存,工作内存)回答
JMM角度的 "主内存" 对应的是硬件角度的 "内存"
"工作内存"对应的是CPU 的寄存器和高速缓存
因为 CPU 访问自身寄存器的速度以及高速缓存的速度, 远远超过访问内存的速度(快了 3 - 4 个数量级, 也就是几千倍, 上万倍).
比如某个代码中要连续 10 次读取某个变量的值, 如果 10 次都从内存读, 速度是很慢的. 但是如果
只是第一次从内存读, 读到的结果缓存到 CPU 的某个寄存器中, 那么后 9 次读数据就不必直接访问
内存了. 效率就大大提高了.
由于CPU从内存存取数据取的太慢,我们就想,可以把这样的数据直接放到寄存器里,后面直接从寄存器中读取,但是这样寄存器空间就太紧张了,于是CPU又另外创建了一个存储空间,这个空间比寄存器大,比内存小,我们叫他缓存(cache),缓存级别分为L1,L2和L3