解决原子性问题,就是要解决CPU中断,但是现在CPU都是多核,因此无法保证多个CPU上的只有一个线程执行

但是在多核场景下,同一时刻,有可能有两个线程同时在执行,一个线程执行在 CPU-1 上,一个线程执行在 CPU-2 上,此时禁止 CPU 中断,只能保证 CPU 上的线程连续执行,并不能保证同一时刻只有一个线程执行,如果这两个线程同时写 long 型变量高 32 位的话,那就有可能出现我们开头提及的诡异 Bug 了。

锁要和锁的资源建立对应的关系,受保护资源和锁之间的关联关系是 N:1 的关系
为了防止自己的锁 锁了别人家的屋子

  1. class SafeCalc {
  2. long value = 0L;
  3. long get() {
  4. return value;
  5. }
  6. synchronized void addOne() {
  7. value += 1;
  8. }
  9. }

被 synchronized 修饰后,无论是单核 CPU 还是多核 CPU,只有一个线程能够执行 addOne() 方法,所以一定能保证原子操作

课后思考

下面的代码用 synchronized 修饰代码块来尝试解决并发问题,你觉得这个使用方式正确吗?有哪些问题呢?能解决可见性和原子性问题吗?

  1. class SafeCalc {
  2. long value = 0L;
  3. long get() {
  4. synchronized (new Object()) {
  5. return value;
  6. }
  7. }
  8. void addOne() {
  9. synchronized (new Object()) {
  10. value += 1;
  11. }
  12. }
  13. }

解答

锁的不是一个对象,所以无效

问题

synchronized作用于对象和作用于类在底层实现上有什么不同

  1. public static void main(String[] args) {
  2. ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 3, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1));
  3. //任务2
  4. pool.execute(() -> System.out.println("--helloWorld_002--" + Thread.currentThread().getName()));
  5. }