问题:
两个线程对初始值为 0 的静态变量一个做自增,一个做自减,各做 5000 次,结果是 0 吗?
1. 临界区问题分析:
以上的结果可能是正数、负数、零。因为 Java 中对静态变量的自增、自减并不是原子操作,要彻底理解,必须从字节码来进行分析。
(1)一个程序运行多个线程本身是没有问题的
(2)问题出在多个线程访问共享资源
①多个线程读共享资源其实也没有问题
②在多个线程对共享资源读写操作时发送指令交错,就会出现问题
(3)一段代码块内如果存在对共享资源的多线程读写操作,称这段代码块为临界区
2. 竞态条件 Race Condition
二、Synchronized 解决方案 1. 应用之互斥多个线程在临界区内执行,由于代码的执行序列不同而导致结果无法预测,称之为发生了竞态条件
为了避免临界区的竞态条件发生,有多种手段可以达到目的。
(1)阻塞式的解决方案:synchronized、Lock
(2)非阻塞式的解决方案:原子变量
synchronized,即俗称的【对象锁】,它采用互斥的方式让同一时刻至多只有一个线程能持有对象锁,其他线程再想获取这个对象锁时就会阻塞住。这样就能保证拥有锁的线程可以安全的执行临界区内的代码,不用担心线程上下文切换。
2. synchronized注意:
虽然 Java 中互斥和同步都可以采用 synchronized 关键字来完成,但有区别:
(1)互斥是保证临界区的竞态条件发生,同一时刻只能有一个线程执行临界区代码。
(2)同步是由于线程执行的先后顺序不同,需要一个线程等待其他线程运行到某个点。
思考:
synchronized 实际是用对象锁保证了临界区内代码的原子性,临界区内的代码对外是不可分割的,不会被线程切换所打断。
3. 面向对象改进为了加深理解,请思考下面的问题(评论区交流)
(1)如果把 synchronized(obj) 放在 for 循环的外面,如何理解?——原子性
(2)如果 t1 synchronized(obj1),而 t2 synchronized(obj2) 会怎样运作?——锁对象
(2)如果 t1 synchronized(obj1),而 t2 没有加会怎么样?——锁对象
三、方法上的 synchronized
四、变量的线程安全分析



